From 21cfd42a561c5ace875257298a9ac04e5592f528 Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Tue, 3 Aug 2021 19:02:55 +0000 Subject: Deploy mate-desktop/libmateweather to github.com/mate-desktop/libmateweather.git:gh-pages --- .../index.html | 131 + .../report-05c89f.html | 2030 +++++++++++ .../report-51881a.html | 557 +++ .../report-58433f.html | 2030 +++++++++++ .../report-5e587e.html | 917 +++++ .../report-6e16dd.html | 433 +++ .../report-782e59.html | 705 ++++ .../report-9adb28.html | 917 +++++ .../report-cbcf8c.html | 705 ++++ .../report-e37e54.html | 705 ++++ .../report-fe7da3.html | 925 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1324 ++++++++ .../7.html | 876 +++++ .../8.html | 3562 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-1eb8d6.html | 705 ++++ .../report-3e128f.html | 917 +++++ .../report-675f1c.html | 433 +++ .../report-6fd2b9.html | 925 +++++ .../report-718fb3.html | 2030 +++++++++++ .../report-a8dc26.html | 705 ++++ .../report-c4a257.html | 2030 +++++++++++ .../report-dcf210.html | 557 +++ .../report-e08d7a.html | 705 ++++ .../report-fc7007.html | 917 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1324 ++++++++ .../7.html | 876 +++++ .../8.html | 3562 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-206845.html | 917 +++++ .../report-21a996.html | 557 +++ .../report-6098a5.html | 705 ++++ .../report-85a4a0.html | 917 +++++ .../report-8e52c5.html | 2030 +++++++++++ .../report-acbe0b.html | 705 ++++ .../report-c62674.html | 925 +++++ .../report-ddf422.html | 705 ++++ .../report-f64134.html | 2030 +++++++++++ .../report-fc9a6b.html | 433 +++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1368 ++++++++ .../1.html | 994 ++++++ .../2.html | 708 ++++ .../3.html | 330 ++ .../4.html | 350 ++ .../5.html | 336 ++ .../6.html | 1324 ++++++++ .../7.html | 876 +++++ .../8.html | 3562 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-1d4183.html | 917 +++++ .../report-2f253f.html | 705 ++++ .../report-41c11c.html | 705 ++++ .../report-4d1c4e.html | 705 ++++ .../report-66f778.html | 917 +++++ .../report-701e40.html | 2030 +++++++++++ .../report-7c6e31.html | 2030 +++++++++++ .../report-b382d0.html | 925 +++++ .../report-b418d3.html | 433 +++ .../report-ca1ddb.html | 557 +++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3567 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-03a844.html | 2030 +++++++++++ .../report-11b0f0.html | 705 ++++ .../report-158c8f.html | 557 +++ .../report-329e7c.html | 705 ++++ .../report-32a058.html | 925 +++++ .../report-4f3b7a.html | 705 ++++ .../report-7a6cad.html | 917 +++++ .../report-842687.html | 433 +++ .../report-88127a.html | 2030 +++++++++++ .../report-99fc51.html | 917 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3567 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-3078ce.html | 705 ++++ .../report-3da40d.html | 433 +++ .../report-480d79.html | 2031 +++++++++++ .../report-4e0d7a.html | 705 ++++ .../report-70386d.html | 917 +++++ .../report-870b18.html | 557 +++ .../report-abb3a4.html | 705 ++++ .../report-b1abfd.html | 2031 +++++++++++ .../report-d213ed.html | 917 +++++ .../report-e31a51.html | 925 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3569 ++++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-0f24ae.html | 705 ++++ .../report-34fe90.html | 705 ++++ .../report-674ad3.html | 2030 +++++++++++ .../report-73ec36.html | 917 +++++ .../report-7aa71e.html | 433 +++ .../report-91ce4a.html | 557 +++ .../report-98c4b4.html | 2030 +++++++++++ .../report-9b8544.html | 925 +++++ .../report-c70360.html | 705 ++++ .../report-e69ea1.html | 917 +++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3567 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-08820c.html | 925 +++++ .../report-0fa174.html | 917 +++++ .../report-1fe28e.html | 2031 +++++++++++ .../report-7ede98.html | 2031 +++++++++++ .../report-8e8304.html | 705 ++++ .../report-97cae0.html | 433 +++ .../report-9bb40e.html | 557 +++ .../report-a9e237.html | 705 ++++ .../report-c5750f.html | 917 +++++ .../report-db5a47.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3569 ++++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-09e817.html | 2031 +++++++++++ .../report-210b0e.html | 433 +++ .../report-3a350b.html | 917 +++++ .../report-785848.html | 917 +++++ .../report-a3e0b5.html | 925 +++++ .../report-a9527a.html | 705 ++++ .../report-aca8ad.html | 705 ++++ .../report-e6a049.html | 2031 +++++++++++ .../report-e6a499.html | 557 +++ .../report-ff6417.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3569 ++++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + .../index.html | 131 + .../report-276335.html | 917 +++++ .../report-343b66.html | 2029 +++++++++++ .../report-565489.html | 2029 +++++++++++ .../report-a36726.html | 705 ++++ .../report-ae87bd.html | 925 +++++ .../report-c44f01.html | 557 +++ .../report-d61a15.html | 433 +++ .../report-ed04ec.html | 705 ++++ .../report-f2564c.html | 917 +++++ .../report-f91718.html | 705 ++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ .../0.html | 1373 ++++++++ .../1.html | 999 ++++++ .../2.html | 713 ++++ .../3.html | 335 ++ .../4.html | 355 ++ .../5.html | 341 ++ .../6.html | 1329 ++++++++ .../7.html | 881 +++++ .../8.html | 3565 +++++++++++++++++++ .../index.html | 157 + .../stats.html | 116 + .../style.css | 137 + CNAME | 1 + index.html | 46 + 252 files changed, 209040 insertions(+) create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/index.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-05c89f.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-51881a.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-58433f.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-5e587e.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-6e16dd.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-782e59.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-9adb28.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-cbcf8c.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-e37e54.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-fe7da3.html create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/scanview.css create mode 100644 2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/sorttable.js create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/0.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/1.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/2.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/3.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/4.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/5.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/6.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/7.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/8.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/index.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/stats.html create mode 100644 2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/style.css create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/index.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-1eb8d6.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-3e128f.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-675f1c.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-6fd2b9.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-718fb3.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-a8dc26.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-c4a257.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-dcf210.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-e08d7a.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-fc7007.html create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/scanview.css create mode 100644 2021-04-20-120038-5347-1@90cc76a2b0e8_master/sorttable.js create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/0.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/1.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/2.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/3.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/4.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/5.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/6.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/7.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/8.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/index.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/stats.html create mode 100644 2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/style.css create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/index.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-206845.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-21a996.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-6098a5.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-85a4a0.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-8e52c5.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-acbe0b.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-c62674.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-ddf422.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-f64134.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/report-fc9a6b.html create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/scanview.css create mode 100644 2021-04-23-115345-5354-1@507def9fa23c_master/sorttable.js create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/0.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/1.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/2.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/3.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/4.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/5.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/6.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/7.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/8.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/index.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/stats.html create mode 100644 2021-04-23-115451-4865-cppcheck@507def9fa23c_master/style.css create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/index.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-1d4183.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-2f253f.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-41c11c.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-4d1c4e.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-66f778.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-701e40.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-7c6e31.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b382d0.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b418d3.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/report-ca1ddb.html create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/scanview.css create mode 100644 2021-05-29-202947-5783-1@81c4edf62d4f_master/sorttable.js create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/0.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/1.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/2.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/3.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/4.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/5.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/6.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/7.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/8.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/index.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/stats.html create mode 100644 2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/style.css create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/index.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-03a844.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-11b0f0.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-158c8f.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-329e7c.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-32a058.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-4f3b7a.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-7a6cad.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-842687.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-88127a.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/report-99fc51.html create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/scanview.css create mode 100644 2021-07-01-175943-5798-1@94fea1882974_master/sorttable.js create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/0.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/1.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/2.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/3.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/4.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/5.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/6.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/7.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/8.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/index.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/stats.html create mode 100644 2021-07-01-180053-8389-cppcheck@94fea1882974_master/style.css create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/index.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3078ce.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3da40d.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-480d79.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-4e0d7a.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-70386d.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-870b18.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-abb3a4.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-b1abfd.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-d213ed.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-e31a51.html create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/scanview.css create mode 100644 2021-07-01-223449-5793-1@23139abb17f7_libsoup/sorttable.js create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/0.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/1.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/2.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/3.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/4.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/5.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/6.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/7.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/8.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/index.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/stats.html create mode 100644 2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/style.css create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/index.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-0f24ae.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-34fe90.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-674ad3.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-73ec36.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-7aa71e.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-91ce4a.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-98c4b4.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-9b8544.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-c70360.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/report-e69ea1.html create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/scanview.css create mode 100644 2021-07-06-144654-5799-1@74c7f241a34e_master/sorttable.js create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/0.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/1.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/2.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/3.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/4.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/5.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/6.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/7.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/8.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/index.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/stats.html create mode 100644 2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/style.css create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/index.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-08820c.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-0fa174.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-1fe28e.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-7ede98.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-8e8304.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-97cae0.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-9bb40e.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-a9e237.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-c5750f.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/report-db5a47.html create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/scanview.css create mode 100644 2021-07-06-151504-5797-1@c7506693d197_libsoup/sorttable.js create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/0.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/1.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/2.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/3.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/4.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/5.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/6.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/7.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/8.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/index.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/stats.html create mode 100644 2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/style.css create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/index.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-09e817.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-210b0e.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-3a350b.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-785848.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-a3e0b5.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-a9527a.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-aca8ad.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a049.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a499.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/report-ff6417.html create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/scanview.css create mode 100644 2021-07-09-125639-5805-1@c018cd4659d9_master/sorttable.js create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/0.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/1.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/2.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/3.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/4.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/5.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/6.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/7.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/8.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/index.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/stats.html create mode 100644 2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/style.css create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/index.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-276335.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-343b66.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-565489.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-a36726.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ae87bd.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-c44f01.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-d61a15.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ed04ec.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f2564c.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f91718.html create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/scanview.css create mode 100644 2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/sorttable.js create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/0.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/1.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/2.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/3.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/4.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/5.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/6.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/7.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/8.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/index.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/stats.html create mode 100644 2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/style.css create mode 100644 CNAME create mode 100644 index.html diff --git a/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/index.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/index.html new file mode 100644 index 0000000..47bb36a --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@be8c896422b3
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Wed Apr 7 20:25:43 2021
+

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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-05c89f.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-05c89f.html new file mode 100644 index 0000000..27a1d38 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-05c89f.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-51881a.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-51881a.html new file mode 100644 index 0000000..f8dc5de --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-51881a.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-58433f.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-58433f.html new file mode 100644 index 0000000..9896b77 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-58433f.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-5e587e.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-5e587e.html new file mode 100644 index 0000000..a864498 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-5e587e.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-6e16dd.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-6e16dd.html new file mode 100644 index 0000000..685af3f --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-6e16dd.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-782e59.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-782e59.html new file mode 100644 index 0000000..6a8b86a --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-782e59.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-9adb28.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-9adb28.html new file mode 100644 index 0000000..0b3afca --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-9adb28.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-cbcf8c.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-cbcf8c.html new file mode 100644 index 0000000..0d66c52 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-cbcf8c.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-e37e54.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-e37e54.html new file mode 100644 index 0000000..57b7d16 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-e37e54.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-fe7da3.html b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-fe7da3.html new file mode 100644 index 0000000..00c95aa --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/report-fe7da3.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 -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/2021-04-07-202543-5352-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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/scanview.css b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/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/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/sorttable.js b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-04-07-202543-5352-1@eca5311a4fd2_brazil2/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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/1.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/1.html new file mode 100644 index 0000000..c23b73d --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/2.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/2.html new file mode 100644 index 0000000..4a7803f --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/3.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/3.html new file mode 100644 index 0000000..0270c0b --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/4.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/4.html new file mode 100644 index 0000000..a9f2c59 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/5.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/5.html new file mode 100644 index 0000000..594bb07 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/6.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/6.html new file mode 100644 index 0000000..a768bf8 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/6.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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/7.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/7.html new file mode 100644 index 0000000..56c57fd --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/7.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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/8.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/8.html new file mode 100644 index 0000000..c493474 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/8.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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/index.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/index.html new file mode 100644 index 0000000..be43540 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/stats.html b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/style.css b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-04-07-202655-6033-cppcheck@eca5311a4fd2_brazil2/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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/index.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/index.html new file mode 100644 index 0000000..34e8945 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@b4cb820b0a39
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Tue Apr 20 12:00:38 2021
+

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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-1eb8d6.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-1eb8d6.html new file mode 100644 index 0000000..ec56d44 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-1eb8d6.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-3e128f.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-3e128f.html new file mode 100644 index 0000000..ed7cd4d --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-3e128f.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-675f1c.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-675f1c.html new file mode 100644 index 0000000..12241dd --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-675f1c.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-6fd2b9.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-6fd2b9.html new file mode 100644 index 0000000..4d87d53 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-6fd2b9.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-718fb3.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-718fb3.html new file mode 100644 index 0000000..01388ab --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-718fb3.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-a8dc26.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-a8dc26.html new file mode 100644 index 0000000..a91cc59 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-a8dc26.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-c4a257.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-c4a257.html new file mode 100644 index 0000000..5f8e487 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-c4a257.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-dcf210.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-dcf210.html new file mode 100644 index 0000000..860a628 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-dcf210.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-e08d7a.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-e08d7a.html new file mode 100644 index 0000000..73dc6d2 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-e08d7a.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-fc7007.html b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-fc7007.html new file mode 100644 index 0000000..ba903a2 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/report-fc7007.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 -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/2021-04-20-120038-5347-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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/scanview.css b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_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/2021-04-20-120038-5347-1@90cc76a2b0e8_master/sorttable.js b/2021-04-20-120038-5347-1@90cc76a2b0e8_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-04-20-120038-5347-1@90cc76a2b0e8_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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/1.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/1.html new file mode 100644 index 0000000..c23b73d --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/2.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/2.html new file mode 100644 index 0000000..4a7803f --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/3.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/3.html new file mode 100644 index 0000000..0270c0b --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/4.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/4.html new file mode 100644 index 0000000..a9f2c59 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/5.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/5.html new file mode 100644 index 0000000..594bb07 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/6.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/6.html new file mode 100644 index 0000000..a768bf8 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/6.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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/7.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/7.html new file mode 100644 index 0000000..56c57fd --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/7.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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/8.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/8.html new file mode 100644 index 0000000..c493474 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/8.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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/index.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/index.html new file mode 100644 index 0000000..be43540 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/stats.html b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/style.css b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-04-20-120145-5948-cppcheck@90cc76a2b0e8_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/2021-04-23-115345-5354-1@507def9fa23c_master/index.html b/2021-04-23-115345-5354-1@507def9fa23c_master/index.html new file mode 100644 index 0000000..fb79935 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@4da12463a919
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 11.0.0 (Fedora 11.0.0-2.fc33) +
Date:Fri Apr 23 11:53:45 2021
+

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/2021-04-23-115345-5354-1@507def9fa23c_master/report-206845.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-206845.html new file mode 100644 index 0000000..641b009 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-206845.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-21a996.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-21a996.html new file mode 100644 index 0000000..8f25e72 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-21a996.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-6098a5.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-6098a5.html new file mode 100644 index 0000000..5abc7b3 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-6098a5.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-85a4a0.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-85a4a0.html new file mode 100644 index 0000000..c467f41 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-85a4a0.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-8e52c5.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-8e52c5.html new file mode 100644 index 0000000..f69e90d --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-8e52c5.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-acbe0b.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-acbe0b.html new file mode 100644 index 0000000..4545016 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-acbe0b.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-c62674.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-c62674.html new file mode 100644 index 0000000..913d6c2 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-c62674.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-ddf422.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-ddf422.html new file mode 100644 index 0000000..cfa28b2 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-ddf422.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-f64134.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-f64134.html new file mode 100644 index 0000000..d8738ee --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-f64134.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/report-fc9a6b.html b/2021-04-23-115345-5354-1@507def9fa23c_master/report-fc9a6b.html new file mode 100644 index 0000000..5d051b3 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_master/report-fc9a6b.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 -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/2021-04-23-115345-5354-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/2021-04-23-115345-5354-1@507def9fa23c_master/scanview.css b/2021-04-23-115345-5354-1@507def9fa23c_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_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/2021-04-23-115345-5354-1@507def9fa23c_master/sorttable.js b/2021-04-23-115345-5354-1@507def9fa23c_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-04-23-115345-5354-1@507def9fa23c_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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/1.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/1.html new file mode 100644 index 0000000..c23b73d --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/2.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/2.html new file mode 100644 index 0000000..4a7803f --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/3.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/3.html new file mode 100644 index 0000000..0270c0b --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/4.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/4.html new file mode 100644 index 0000000..a9f2c59 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/5.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/5.html new file mode 100644 index 0000000..594bb07 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/6.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/6.html new file mode 100644 index 0000000..a768bf8 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/6.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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/7.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/7.html new file mode 100644 index 0000000..56c57fd --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/7.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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/8.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/8.html new file mode 100644 index 0000000..c493474 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/8.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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/index.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/index.html new file mode 100644 index 0000000..be43540 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/stats.html b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/style.css b/2021-04-23-115451-4865-cppcheck@507def9fa23c_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-04-23-115451-4865-cppcheck@507def9fa23c_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/2021-05-29-202947-5783-1@81c4edf62d4f_master/index.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/index.html new file mode 100644 index 0000000..68800bd --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@3b8168b20e32
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-0.3.rc1.fc34) +
Date:Sat May 29 20:29:47 2021
+

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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-1d4183.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-1d4183.html new file mode 100644 index 0000000..0264fc5 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-1d4183.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-2f253f.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-2f253f.html new file mode 100644 index 0000000..6d2922c --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-2f253f.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-41c11c.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-41c11c.html new file mode 100644 index 0000000..77eb9c8 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-41c11c.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-4d1c4e.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-4d1c4e.html new file mode 100644 index 0000000..219ec36 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-4d1c4e.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-66f778.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-66f778.html new file mode 100644 index 0000000..0304280 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-66f778.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-701e40.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-701e40.html new file mode 100644 index 0000000..d5af5cf --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-701e40.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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)((__typeof__ (clone->radar)) (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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-7c6e31.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-7c6e31.html new file mode 100644 index 0000000..d822cc6 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-7c6e31.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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)((__typeof__ (clone->radar)) (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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b382d0.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b382d0.html new file mode 100644 index 0000000..99bd2fb --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b382d0.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b418d3.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b418d3.html new file mode 100644 index 0000000..31e3dd4 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-b418d3.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-ca1ddb.html b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-ca1ddb.html new file mode 100644 index 0000000..dd2405b --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_master/report-ca1ddb.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-05-29-202947-5783-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/2021-05-29-202947-5783-1@81c4edf62d4f_master/scanview.css b/2021-05-29-202947-5783-1@81c4edf62d4f_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_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/2021-05-29-202947-5783-1@81c4edf62d4f_master/sorttable.js b/2021-05-29-202947-5783-1@81c4edf62d4f_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-05-29-202947-5783-1@81c4edf62d4f_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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/1.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/1.html new file mode 100644 index 0000000..ac55286 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/2.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/2.html new file mode 100644 index 0000000..aa1947f --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/3.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/3.html new file mode 100644 index 0000000..2241486 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/4.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/4.html new file mode 100644 index 0000000..f97ceac --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/5.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/5.html new file mode 100644 index 0000000..266fa8f --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/6.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/6.html new file mode 100644 index 0000000..f91e258 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/7.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/7.html new file mode 100644 index 0000000..929846f --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/8.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/8.html new file mode 100644 index 0000000..afc51f3 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/8.html @@ -0,0 +1,3567 @@ + + + + + + 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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/index.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/index.html new file mode 100644 index 0000000..be43540 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/stats.html b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/style.css b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-05-29-203055-3020-cppcheck@81c4edf62d4f_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/2021-07-01-175943-5798-1@94fea1882974_master/index.html b/2021-07-01-175943-5798-1@94fea1882974_master/index.html new file mode 100644 index 0000000..f6c121d --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@ac29aaf74efc
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-2.fc34) +
Date:Thu Jul 1 17:59:43 2021
+

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/2021-07-01-175943-5798-1@94fea1882974_master/report-03a844.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-03a844.html new file mode 100644 index 0000000..876df47 --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-03a844.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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)((__typeof__ (clone->radar)) (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/2021-07-01-175943-5798-1@94fea1882974_master/report-11b0f0.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-11b0f0.html new file mode 100644 index 0000000..82e2d9c --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-11b0f0.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-158c8f.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-158c8f.html new file mode 100644 index 0000000..97b6fb5 --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-158c8f.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-329e7c.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-329e7c.html new file mode 100644 index 0000000..4dd597b --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-329e7c.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-32a058.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-32a058.html new file mode 100644 index 0000000..0810eb8 --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-32a058.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-4f3b7a.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-4f3b7a.html new file mode 100644 index 0000000..9bf719f --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-4f3b7a.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-7a6cad.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-7a6cad.html new file mode 100644 index 0000000..58d635c --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-7a6cad.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-842687.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-842687.html new file mode 100644 index 0000000..004dc7d --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-842687.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/report-88127a.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-88127a.html new file mode 100644 index 0000000..56d5527 --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-88127a.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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)((__typeof__ (clone->radar)) (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/2021-07-01-175943-5798-1@94fea1882974_master/report-99fc51.html b/2021-07-01-175943-5798-1@94fea1882974_master/report-99fc51.html new file mode 100644 index 0000000..5ee56fe --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_master/report-99fc51.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-175943-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/2021-07-01-175943-5798-1@94fea1882974_master/scanview.css b/2021-07-01-175943-5798-1@94fea1882974_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_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/2021-07-01-175943-5798-1@94fea1882974_master/sorttable.js b/2021-07-01-175943-5798-1@94fea1882974_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-07-01-175943-5798-1@94fea1882974_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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/1.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/1.html new file mode 100644 index 0000000..ac55286 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/2.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/2.html new file mode 100644 index 0000000..aa1947f --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/3.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/3.html new file mode 100644 index 0000000..2241486 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/4.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/4.html new file mode 100644 index 0000000..f97ceac --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/5.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/5.html new file mode 100644 index 0000000..266fa8f --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/6.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/6.html new file mode 100644 index 0000000..f91e258 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/7.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/7.html new file mode 100644 index 0000000..929846f --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/8.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/8.html new file mode 100644 index 0000000..afc51f3 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/8.html @@ -0,0 +1,3567 @@ + + + + + + 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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/index.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/index.html new file mode 100644 index 0000000..be43540 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/stats.html b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-07-01-180053-8389-cppcheck@94fea1882974_master/style.css b/2021-07-01-180053-8389-cppcheck@94fea1882974_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-07-01-180053-8389-cppcheck@94fea1882974_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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/index.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/index.html new file mode 100644 index 0000000..4fff9df --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@c12755b25568
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-2.fc34) +
Date:Thu Jul 1 22:34:49 2021
+

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_update7261View 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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3078ce.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3078ce.html new file mode 100644 index 0000000..458bb72 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3078ce.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3da40d.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3da40d.html new file mode 100644 index 0000000..1f8e274 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-3da40d.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-480d79.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-480d79.html new file mode 100644 index 0000000..3300a2d --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-480d79.html @@ -0,0 +1,2031 @@ + + + +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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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 g_object_set (G_OBJECT (info->session)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
info->session)), (((GType) ((20) << (2))))))))
, "ssl-use-system-ca-file", TRUE(!(0)), NULL((void*)0));
559 }
560
561 metar_start_open (info);
562 iwin_start_open (info);
563
564 if (prefs->radar) {
565 wx_start_open (info);
566 }
567
568 return info;
569}
570
571void
572weather_info_abort (WeatherInfo *info)
573{
574 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)
;
575
576 if (info->session) {
577 soup_session_abort (info->session);
578 info->requests_pending = 0;
579 }
580}
581
582WeatherInfo *
583weather_info_clone (const WeatherInfo *info)
584{
585 WeatherInfo *clone;
586
587 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
588
589 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; }))
;
590
591
592 /* move everything */
593 memmove (clone, info, sizeof (WeatherInfo));
594
595
596 /* special moves */
597 clone->location = weather_location_clone (info->location);
598 /* This handles null correctly */
599 clone->forecast = g_strdup (info->forecast);
600 clone->radar_url = g_strdup (info->radar_url);
601
602 if (info->forecast_list) {
603 GSList *p;
604
605 clone->forecast_list = NULL((void*)0);
606 for (p = info->forecast_list; p; p = p->next) {
607 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
608 }
609
610 clone->forecast_list = g_slist_reverse (clone->forecast_list);
611 }
612
613 clone->radar = info->radar;
614 if (clone->radar != NULL((void*)0))
615 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
616
617 return clone;
618}
619
620void
621weather_info_free (WeatherInfo *info)
622{
623 if (!info)
624 return;
625
626 weather_info_abort (info);
627 if (info->session)
628 g_object_unref (info->session);
629
630 weather_location_free (info->location);
631 info->location = NULL((void*)0);
632
633 g_free (info->forecast);
634 info->forecast = NULL((void*)0);
635
636 free_forecast_list (info);
637
638 if (info->radar != NULL((void*)0)) {
639 g_object_unref (info->radar);
640 info->radar = NULL((void*)0);
641 }
642
643 g_free (info);
644}
645
646gboolean
647weather_info_is_valid (WeatherInfo *info)
648{
649 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
650 return info->valid;
651}
652
653gboolean
654weather_info_network_error (WeatherInfo *info)
655{
656 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
657 return info->network_error;
658}
659
660void
661weather_info_to_metric (WeatherInfo *info)
662{
663 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)
;
664
665 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
666 info->speed_unit = SPEED_UNIT_MS;
667 info->pressure_unit = PRESSURE_UNIT_HPA;
668 info->distance_unit = DISTANCE_UNIT_METERS;
669}
670
671void
672weather_info_to_imperial (WeatherInfo *info)
673{
674 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)
;
675
676 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
677 info->speed_unit = SPEED_UNIT_MPH;
678 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
679 info->distance_unit = DISTANCE_UNIT_MILES;
680}
681
682const WeatherLocation *
683weather_info_get_location (WeatherInfo *info)
684{
685 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
686 return info->location;
687}
688
689const gchar *
690weather_info_get_location_name (WeatherInfo *info)
691{
692 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
693 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)
;
694 return info->location->name;
695}
696
697const gchar *
698weather_info_get_update (WeatherInfo *info)
699{
700 static gchar buf[200];
701 char *utf8, *timeformat;
702
703 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
704
705 if (!info->valid)
706 return "-";
707
708 if (info->update != 0) {
709 struct tm tm;
710 localtime_r (&info->update, &tm);
711 /* Translators: this is a format string for strftime
712 * see `man 3 strftime` for more details
713 */
714 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
715 NULL((void*)0), NULL((void*)0), NULL((void*)0));
716 if (!timeformat) {
717 strcpy (buf, "???");
718 }
719 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
720 strcpy (buf, "???");
721 }
722 g_free (timeformat);
723
724 /* Convert to UTF-8 */
725 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
726 strcpy (buf, utf8);
727 g_free (utf8);
728 } else {
729 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
730 buf[sizeof (buf)-1] = '\0';
731 }
732
733 return buf;
734}
735
736const gchar *
737weather_info_get_sky (WeatherInfo *info)
738{
739 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
740 if (!info->valid)
741 return "-";
742 if (info->sky < 0)
743 return _("Unknown")(mateweather_gettext ("Unknown"));
744 return weather_sky_string (info->sky);
745}
746
747const gchar *
748weather_info_get_conditions (WeatherInfo *info)
749{
750 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
751 if (!info->valid)
752 return "-";
753 return weather_conditions_string (info->cond);
754}
755
756static const gchar *
757temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
758{
759 static gchar buf[100];
760
761 switch (to_unit) {
762 case TEMP_UNIT_FAHRENHEIT:
763 if (!want_round) {
764 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
765 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
766 } else {
767 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
768 gdouble temp_r;
769
770 feclearexcept(range_problem);
771 temp_r = round (temp);
772 if (fetestexcept(range_problem))
773 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
774 else
775 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
776 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
777 }
778 break;
779 case TEMP_UNIT_CENTIGRADE:
780 if (!want_round) {
781 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
782 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)));
783 } else {
784 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
785 gdouble temp_r;
786
787 feclearexcept(range_problem);
788 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
789 if (fetestexcept(range_problem))
790 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
791 else
792 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
793 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
794 }
795 break;
796 case TEMP_UNIT_KELVIN:
797 if (!want_round) {
798 /* Translators: This is the temperature in kelvin */
799 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
800 } else {
801 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
802 gdouble temp_r;
803
804 feclearexcept(range_problem);
805 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
806 if (fetestexcept(range_problem))
807 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
808 else
809 /* Translators: This is the temperature in kelvin */
810 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
811 }
812 break;
813
814 case TEMP_UNIT_INVALID:
815 case TEMP_UNIT_DEFAULT:
816 default:
817 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
818 return _("Unknown")(mateweather_gettext ("Unknown"));
819 }
820
821 return buf;
822}
823
824const gchar *
825weather_info_get_temp (WeatherInfo *info)
826{
827 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
828
829 if (!info->valid)
830 return "-";
831 if (info->temp < -500.0)
832 return _("Unknown")(mateweather_gettext ("Unknown"));
833
834 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
835}
836
837const gchar *
838weather_info_get_temp_min (WeatherInfo *info)
839{
840 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
841
842 if (!info->valid || !info->tempMinMaxValid)
843 return "-";
844 if (info->temp_min < -500.0)
845 return _("Unknown")(mateweather_gettext ("Unknown"));
846
847 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
848}
849
850const gchar *
851weather_info_get_temp_max (WeatherInfo *info)
852{
853 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
854
855 if (!info->valid || !info->tempMinMaxValid)
856 return "-";
857 if (info->temp_max < -500.0)
858 return _("Unknown")(mateweather_gettext ("Unknown"));
859
860 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
861}
862
863const gchar *
864weather_info_get_dew (WeatherInfo *info)
865{
866 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
867
868 if (!info->valid)
869 return "-";
870 if (info->dew < -500.0)
871 return _("Unknown")(mateweather_gettext ("Unknown"));
872
873 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
874}
875
876const gchar *
877weather_info_get_humidity (WeatherInfo *info)
878{
879 static gchar buf[20];
880 gdouble humidity;
881
882 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
883
884 if (!info->valid)
885 return "-";
886
887 humidity = calc_humidity (info->temp, info->dew);
888 if (humidity < 0.0)
889 return _("Unknown")(mateweather_gettext ("Unknown"));
890
891 /* Translators: This is the humidity in percent */
892 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
893 return buf;
894}
895
896const gchar *
897weather_info_get_apparent (WeatherInfo *info)
898{
899 gdouble apparent;
900
901 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
902 if (!info->valid)
903 return "-";
904
905 apparent = calc_apparent (info);
906 if (apparent < -500.0)
907 return _("Unknown")(mateweather_gettext ("Unknown"));
908
909 return temperature_string (apparent, info->temperature_unit, FALSE(0));
910}
911
912static const gchar *
913windspeed_string (gfloat knots, SpeedUnit to_unit)
914{
915 static gchar buf[100];
916
917 switch (to_unit) {
918 case SPEED_UNIT_KNOTS:
919 /* Translators: This is the wind speed in knots */
920 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
921 break;
922 case SPEED_UNIT_MPH:
923 /* Translators: This is the wind speed in miles per hour */
924 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
925 break;
926 case SPEED_UNIT_KPH:
927 /* Translators: This is the wind speed in kilometers per hour */
928 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
929 break;
930 case SPEED_UNIT_MS:
931 /* Translators: This is the wind speed in meters per second */
932 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
933 break;
934 case SPEED_UNIT_BFT:
935 /* Translators: This is the wind speed as a Beaufort force factor
936 * (commonly used in nautical wind estimation).
937 */
938 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
939 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
940 break;
941 case SPEED_UNIT_INVALID:
942 case SPEED_UNIT_DEFAULT:
943 default:
944 g_warning ("Conversion to illegal speed unit: %d", to_unit);
945 return _("Unknown")(mateweather_gettext ("Unknown"));
946 }
947
948 return buf;
949}
950
951const gchar *
952weather_info_get_wind (WeatherInfo *info)
953{
954 static gchar buf[200];
955
956 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
957
958 if (!info->valid)
959 return "-";
960 if (info->windspeed < 0.0 || info->wind < 0)
961 return _("Unknown")(mateweather_gettext ("Unknown"));
962 if (info->windspeed == 0.00) {
963 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
964 buf[sizeof (buf)-1] = '\0';
965 } else {
966 /* Translators: This is 'wind direction' / 'wind speed' */
967 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
968 weather_wind_direction_string (info->wind),
969 windspeed_string (info->windspeed, info->speed_unit));
970 }
971 return buf;
972}
973
974const gchar *
975weather_info_get_pressure (WeatherInfo *info)
976{
977 static gchar buf[100];
978
979 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
980
981 if (!info->valid)
982 return "-";
983 if (info->pressure < 0.0)
984 return _("Unknown")(mateweather_gettext ("Unknown"));
985
986 switch (info->pressure_unit) {
987 case PRESSURE_UNIT_INCH_HG:
988 /* Translators: This is pressure in inches of mercury */
989 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
990 break;
991 case PRESSURE_UNIT_MM_HG:
992 /* Translators: This is pressure in millimeters of mercury */
993 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
994 break;
995 case PRESSURE_UNIT_KPA:
996 /* Translators: This is pressure in kiloPascals */
997 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
998 break;
999 case PRESSURE_UNIT_HPA:
1000 /* Translators: This is pressure in hectoPascals */
1001 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1002 break;
1003 case PRESSURE_UNIT_MB:
1004 /* Translators: This is pressure in millibars */
1005 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1006 break;
1007 case PRESSURE_UNIT_ATM:
1008 /* Translators: This is pressure in atmospheres */
1009 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1010 break;
1011
1012 case PRESSURE_UNIT_INVALID:
1013 case PRESSURE_UNIT_DEFAULT:
1014 default:
1015 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1016 return _("Unknown")(mateweather_gettext ("Unknown"));
1017 }
1018
1019 return buf;
1020}
1021
1022const gchar *
1023weather_info_get_visibility (WeatherInfo *info)
1024{
1025 static gchar buf[100];
1026
1027 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1028
1029 if (!info->valid)
1030 return "-";
1031 if (info->visibility < 0.0)
1032 return _("Unknown")(mateweather_gettext ("Unknown"));
1033
1034 switch (info->distance_unit) {
1035 case DISTANCE_UNIT_MILES:
1036 /* Translators: This is the visibility in miles */
1037 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1038 break;
1039 case DISTANCE_UNIT_KM:
1040 /* Translators: This is the visibility in kilometers */
1041 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1042 break;
1043 case DISTANCE_UNIT_METERS:
1044 /* Translators: This is the visibility in meters */
1045 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1046 break;
1047
1048 case DISTANCE_UNIT_INVALID:
1049 case DISTANCE_UNIT_DEFAULT:
1050 default:
1051 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1052 return _("Unknown")(mateweather_gettext ("Unknown"));
1053 }
1054
1055 return buf;
1056}
1057
1058const gchar *
1059weather_info_get_sunrise (WeatherInfo *info)
1060{
1061 static gchar buf[200];
1062 struct tm tm;
1063
1064 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)
;
1065
1066 if (!info->location->latlon_valid)
1067 return "-";
1068 if (!info->valid)
1069 return "-";
1070 if (!calc_sun (info))
1071 return "-";
1072
1073 localtime_r (&info->sunrise, &tm);
1074 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1075 return "-";
1076 return buf;
1077}
1078
1079const gchar *
1080weather_info_get_sunset (WeatherInfo *info)
1081{
1082 static gchar buf[200];
1083 struct tm tm;
1084
1085 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)
;
1086
1087 if (!info->location->latlon_valid)
1088 return "-";
1089 if (!info->valid)
1090 return "-";
1091 if (!calc_sun (info))
1092 return "-";
1093
1094 localtime_r (&info->sunset, &tm);
1095 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1096 return "-";
1097 return buf;
1098}
1099
1100const gchar *
1101weather_info_get_forecast (WeatherInfo *info)
1102{
1103 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1104 return info->forecast;
1105}
1106
1107/**
1108 * weather_info_get_forecast_list:
1109 * Returns list of WeatherInfo* objects for the forecast.
1110 * The list is owned by the 'info' object thus is alive as long
1111 * as the 'info'. This list is filled only when requested with
1112 * type FORECAST_LIST and if available for given location.
1113 * The 'update' property is the date/time when the forecast info
1114 * is used for.
1115 **/
1116GSList *
1117weather_info_get_forecast_list (WeatherInfo *info)
1118{
1119 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1120
1121 if (!info->valid)
1122 return NULL((void*)0);
1123
1124 return info->forecast_list;
1125}
1126
1127GdkPixbufAnimation *
1128weather_info_get_radar (WeatherInfo *info)
1129{
1130 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1131 return info->radar;
1132}
1133
1134const gchar *
1135weather_info_get_temp_summary (WeatherInfo *info)
1136{
1137 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1138
1139 if (!info->valid || info->temp < -500.0)
1140 return "--";
1141
1142 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1143
1144}
1145
1146gchar *
1147weather_info_get_weather_summary (WeatherInfo *info)
1148{
1149 const gchar *buf;
1150
1151 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1152
1153 if (!info->valid)
1154 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1155 buf = weather_info_get_conditions (info);
1156 if (!strcmp (buf, "-"))
1157 buf = weather_info_get_sky (info);
1158 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1159}
1160
1161const gchar *
1162weather_info_get_icon_name (WeatherInfo *info)
1163{
1164 WeatherConditions cond;
1165 WeatherSky sky;
1166 time_t current_time;
1167 gboolean daytime;
1168 gchar* icon;
1169 static gchar icon_buffer[32];
1170 WeatherMoonPhase moonPhase;
1171 WeatherMoonLatitude moonLat;
1172 gint phase;
1173
1174 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1175
1176 if (!info->valid)
1177 return NULL((void*)0);
1178
1179 cond = info->cond;
1180 sky = info->sky;
1181
1182 if (cond.significant) {
1183 if (cond.phenomenon != PHENOMENON_NONE &&
1184 cond.qualifier == QUALIFIER_THUNDERSTORM)
1185 return "weather-storm";
1186
1187 switch (cond.phenomenon) {
1188 case PHENOMENON_INVALID:
1189 case PHENOMENON_LAST:
1190 case PHENOMENON_NONE:
1191 break;
1192
1193 case PHENOMENON_DRIZZLE:
1194 case PHENOMENON_RAIN:
1195 case PHENOMENON_UNKNOWN_PRECIPITATION:
1196 case PHENOMENON_HAIL:
1197 case PHENOMENON_SMALL_HAIL:
1198 return "weather-showers";
1199
1200 case PHENOMENON_SNOW:
1201 case PHENOMENON_SNOW_GRAINS:
1202 case PHENOMENON_ICE_PELLETS:
1203 case PHENOMENON_ICE_CRYSTALS:
1204 return "weather-snow";
1205
1206 case PHENOMENON_TORNADO:
1207 case PHENOMENON_SQUALL:
1208 return "weather-storm";
1209
1210 case PHENOMENON_MIST:
1211 case PHENOMENON_FOG:
1212 case PHENOMENON_SMOKE:
1213 case PHENOMENON_VOLCANIC_ASH:
1214 case PHENOMENON_SAND:
1215 case PHENOMENON_HAZE:
1216 case PHENOMENON_SPRAY:
1217 case PHENOMENON_DUST:
1218 case PHENOMENON_SANDSTORM:
1219 case PHENOMENON_DUSTSTORM:
1220 case PHENOMENON_FUNNEL_CLOUD:
1221 case PHENOMENON_DUST_WHIRLS:
1222 return "weather-fog";
1223 }
1224 }
1225
1226 if (info->midnightSun ||
1227 (!info->sunriseValid && !info->sunsetValid))
1228 daytime = TRUE(!(0));
1229 else if (info->polarNight)
1230 daytime = FALSE(0);
1231 else {
1232 current_time = time (NULL((void*)0));
1233 daytime =
1234 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1235 ( !info->sunsetValid || (current_time < info->sunset) );
1236 }
1237
1238 switch (sky) {
1239 case SKY_INVALID:
1240 case SKY_LAST:
1241 case SKY_CLEAR:
1242 if (daytime)
1243 return "weather-clear";
1244 else {
1245 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1246 break;
1247 }
1248
1249 case SKY_BROKEN:
1250 case SKY_SCATTERED:
1251 case SKY_FEW:
1252 if (daytime)
1253 return "weather-few-clouds";
1254 else {
1255 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1256 break;
1257 }
1258
1259 case SKY_OVERCAST:
1260 return "weather-overcast";
1261
1262 default: /* unrecognized */
1263 return NULL((void*)0);
1264 }
1265
1266 /*
1267 * A phase-of-moon icon is to be returned.
1268 * Determine which one based on the moon's location
1269 */
1270 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1271 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1272 if (phase == MOON_PHASES36) {
1273 phase = 0;
1274 } else if (phase > 0 &&
1275 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1276 < moonLat)) {
1277 /*
1278 * Locations south of the moon's latitude will see the moon in the
1279 * northern sky. The moon waxes and wanes from left to right
1280 * so we reference an icon running in the opposite direction.
1281 */
1282 phase = MOON_PHASES36 - phase;
1283 }
1284
1285 /*
1286 * If the moon is not full then append the angle to the icon string.
1287 * Note that an icon by this name is not required to exist:
1288 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1289 * the full moon image.
1290 */
1291 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1292 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1293 "-%03d", phase * 360 / MOON_PHASES36);
1294 }
1295 }
1296 return icon_buffer;
1297}
1298
1299static gboolean
1300temperature_value (gdouble temp_f,
1301 TempUnit to_unit,
1302 gdouble *value,
1303 TempUnit def_unit)
1304{
1305 gboolean ok = TRUE(!(0));
1306
1307 *value = 0.0;
1308 if (temp_f < -500.0)
1309 return FALSE(0);
1310
1311 if (to_unit == TEMP_UNIT_DEFAULT)
1312 to_unit = def_unit;
1313
1314 switch (to_unit) {
1315 case TEMP_UNIT_FAHRENHEIT:
1316 *value = temp_f;
1317 break;
1318 case TEMP_UNIT_CENTIGRADE:
1319 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1320 break;
1321 case TEMP_UNIT_KELVIN:
1322 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1323 break;
1324 case TEMP_UNIT_INVALID:
1325 case TEMP_UNIT_DEFAULT:
1326 default:
1327 ok = FALSE(0);
1328 break;
1329 }
1330
1331 return ok;
1332}
1333
1334static gboolean
1335speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1336{
1337 gboolean ok = TRUE(!(0));
1338
1339 *value = -1.0;
1340
1341 if (knots < 0.0)
1342 return FALSE(0);
1343
1344 if (to_unit == SPEED_UNIT_DEFAULT)
1345 to_unit = def_unit;
1346
1347 switch (to_unit) {
1348 case SPEED_UNIT_KNOTS:
1349 *value = knots;
1350 break;
1351 case SPEED_UNIT_MPH:
1352 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1353 break;
1354 case SPEED_UNIT_KPH:
1355 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1356 break;
1357 case SPEED_UNIT_MS:
1358 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1359 break;
1360 case SPEED_UNIT_BFT:
1361 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1362 break;
1363 case SPEED_UNIT_INVALID:
1364 case SPEED_UNIT_DEFAULT:
1365 default:
1366 ok = FALSE(0);
1367 break;
1368 }
1369
1370 return ok;
1371}
1372
1373static gboolean
1374pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1375{
1376 gboolean ok = TRUE(!(0));
1377
1378 *value = -1.0;
1379
1380 if (inHg < 0.0)
1381 return FALSE(0);
1382
1383 if (to_unit == PRESSURE_UNIT_DEFAULT)
1384 to_unit = def_unit;
1385
1386 switch (to_unit) {
1387 case PRESSURE_UNIT_INCH_HG:
1388 *value = inHg;
1389 break;
1390 case PRESSURE_UNIT_MM_HG:
1391 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1392 break;
1393 case PRESSURE_UNIT_KPA:
1394 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1395 break;
1396 case PRESSURE_UNIT_HPA:
1397 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1398 break;
1399 case PRESSURE_UNIT_MB:
1400 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1401 break;
1402 case PRESSURE_UNIT_ATM:
1403 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1404 break;
1405 case PRESSURE_UNIT_INVALID:
1406 case PRESSURE_UNIT_DEFAULT:
1407 default:
1408 ok = FALSE(0);
1409 break;
1410 }
1411
1412 return ok;
1413}
1414
1415static gboolean
1416distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1417{
1418 gboolean ok = TRUE(!(0));
1419
1420 *value = -1.0;
1421
1422 if (miles < 0.0)
1423 return FALSE(0);
1424
1425 if (to_unit == DISTANCE_UNIT_DEFAULT)
1426 to_unit = def_unit;
1427
1428 switch (to_unit) {
1429 case DISTANCE_UNIT_MILES:
1430 *value = miles;
1431 break;
1432 case DISTANCE_UNIT_KM:
1433 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1434 break;
1435 case DISTANCE_UNIT_METERS:
1436 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1437 break;
1438 case DISTANCE_UNIT_INVALID:
1439 case DISTANCE_UNIT_DEFAULT:
1440 default:
1441 ok = FALSE(0);
1442 break;
1443 }
1444
1445 return ok;
1446}
1447
1448gboolean
1449weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1450{
1451 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1452 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)
;
1453
1454 if (!info->valid)
1455 return FALSE(0);
1456
1457 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1458 return FALSE(0);
1459
1460 *sky = info->sky;
1461
1462 return TRUE(!(0));
1463}
1464
1465gboolean
1466weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1467{
1468 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1469 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)
;
1470 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)
;
1471
1472 if (!info->valid)
1473 return FALSE(0);
1474
1475 if (!info->cond.significant)
1476 return FALSE(0);
1477
1478 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1479 info->cond.phenomenon < PHENOMENON_LAST &&
1480 info->cond.qualifier > QUALIFIER_INVALID &&
1481 info->cond.qualifier < QUALIFIER_LAST))
1482 return FALSE(0);
1483
1484 *phenomenon = info->cond.phenomenon;
1485 *qualifier = info->cond.qualifier;
1486
1487 return TRUE(!(0));
1488}
1489
1490gboolean
1491weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1492{
1493 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1494 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)
;
1495
1496 if (!info->valid)
1497 return FALSE(0);
1498
1499 return temperature_value (info->temp, unit, value, info->temperature_unit);
1500}
1501
1502gboolean
1503weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1504{
1505 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1506 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)
;
1507
1508 if (!info->valid || !info->tempMinMaxValid)
1509 return FALSE(0);
1510
1511 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1512}
1513
1514gboolean
1515weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1516{
1517 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1518 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)
;
1519
1520 if (!info->valid || !info->tempMinMaxValid)
1521 return FALSE(0);
1522
1523 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1524}
1525
1526gboolean
1527weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1528{
1529 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1530 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)
;
1531
1532 if (!info->valid)
1533 return FALSE(0);
1534
1535 return temperature_value (info->dew, unit, value, info->temperature_unit);
1536}
1537
1538gboolean
1539weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1540{
1541 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1542 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)
;
1543
1544 if (!info->valid)
1545 return FALSE(0);
1546
1547 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1548}
1549
1550gboolean
1551weather_info_get_value_update (WeatherInfo *info, time_t *value)
1552{
1553 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1554 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)
;
1555
1556 if (!info->valid)
1557 return FALSE(0);
1558
1559 *value = info->update;
1560
1561 return TRUE(!(0));
1562}
1563
1564gboolean
1565weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1566{
1567 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1568 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)
;
1569
1570 if (!info->valid || !info->sunriseValid)
1571 return FALSE(0);
1572
1573 *value = info->sunrise;
1574
1575 return TRUE(!(0));
1576}
1577
1578gboolean
1579weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1580{
1581 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1582 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)
;
1583
1584 if (!info->valid || !info->sunsetValid)
1585 return FALSE(0);
1586
1587 *value = info->sunset;
1588
1589 return TRUE(!(0));
1590}
1591
1592gboolean
1593weather_info_get_value_moonphase (WeatherInfo *info,
1594 WeatherMoonPhase *value,
1595 WeatherMoonLatitude *lat)
1596{
1597 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1598 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)
;
1599
1600 if (!info->valid || !info->moonValid)
1601 return FALSE(0);
1602
1603 *value = info->moonphase;
1604 *lat = info->moonlatitude;
1605
1606 return TRUE(!(0));
1607}
1608
1609gboolean
1610weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1611{
1612 gboolean res = FALSE(0);
1613
1614 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1615 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)
;
1616 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)
;
1617
1618 if (!info->valid)
1619 return FALSE(0);
1620
1621 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1622 return FALSE(0);
1623
1624 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1625 *direction = info->wind;
1626
1627 return res;
1628}
1629
1630gboolean
1631weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1632{
1633 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1634 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)
;
1635
1636 if (!info->valid)
1637 return FALSE(0);
1638
1639 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1640}
1641
1642gboolean
1643weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1644{
1645 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1646 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)
;
1647
1648 if (!info->valid)
1649 return FALSE(0);
1650
1651 return distance_value (info->visibility, unit, value, info->distance_unit);
1652}
1653
1654/**
1655 * weather_info_get_upcoming_moonphases:
1656 * @info: WeatherInfo containing the time_t of interest
1657 * @phases: An array of four time_t values that will hold the returned values.
1658 * The values are estimates of the time of the next new, quarter, full and
1659 * three-quarter moons.
1660 *
1661 * Returns: gboolean indicating success or failure
1662 */
1663gboolean
1664weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1665{
1666 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1667 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)
;
1668
1669 return calc_moon_phases(info, phases);
1670}
1671
1672static void
1673_weather_internal_check (void)
1674{
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1676 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"
, 1676, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1677 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", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1678 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", 1678, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1679}
diff --git a/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-4e0d7a.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-4e0d7a.html new file mode 100644 index 0000000..dd41f86 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-4e0d7a.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-70386d.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-70386d.html new file mode 100644 index 0000000..f8e7eae --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-70386d.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-870b18.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-870b18.html new file mode 100644 index 0000000..1a0ac3b --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-870b18.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-abb3a4.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-abb3a4.html new file mode 100644 index 0000000..9eec674 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-abb3a4.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-b1abfd.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-b1abfd.html new file mode 100644 index 0000000..f9d8fb5 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-b1abfd.html @@ -0,0 +1,2031 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 726, 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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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 g_object_set (G_OBJECT (info->session)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
info->session)), (((GType) ((20) << (2))))))))
, "ssl-use-system-ca-file", TRUE(!(0)), NULL((void*)0));
559 }
560
561 metar_start_open (info);
562 iwin_start_open (info);
563
564 if (prefs->radar) {
565 wx_start_open (info);
566 }
567
568 return info;
569}
570
571void
572weather_info_abort (WeatherInfo *info)
573{
574 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)
;
575
576 if (info->session) {
577 soup_session_abort (info->session);
578 info->requests_pending = 0;
579 }
580}
581
582WeatherInfo *
583weather_info_clone (const WeatherInfo *info)
584{
585 WeatherInfo *clone;
586
587 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
588
589 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; }))
;
590
591
592 /* move everything */
593 memmove (clone, info, sizeof (WeatherInfo));
594
595
596 /* special moves */
597 clone->location = weather_location_clone (info->location);
598 /* This handles null correctly */
599 clone->forecast = g_strdup (info->forecast);
600 clone->radar_url = g_strdup (info->radar_url);
601
602 if (info->forecast_list) {
603 GSList *p;
604
605 clone->forecast_list = NULL((void*)0);
606 for (p = info->forecast_list; p; p = p->next) {
607 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
608 }
609
610 clone->forecast_list = g_slist_reverse (clone->forecast_list);
611 }
612
613 clone->radar = info->radar;
614 if (clone->radar != NULL((void*)0))
615 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
616
617 return clone;
618}
619
620void
621weather_info_free (WeatherInfo *info)
622{
623 if (!info)
624 return;
625
626 weather_info_abort (info);
627 if (info->session)
628 g_object_unref (info->session);
629
630 weather_location_free (info->location);
631 info->location = NULL((void*)0);
632
633 g_free (info->forecast);
634 info->forecast = NULL((void*)0);
635
636 free_forecast_list (info);
637
638 if (info->radar != NULL((void*)0)) {
639 g_object_unref (info->radar);
640 info->radar = NULL((void*)0);
641 }
642
643 g_free (info);
644}
645
646gboolean
647weather_info_is_valid (WeatherInfo *info)
648{
649 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
650 return info->valid;
651}
652
653gboolean
654weather_info_network_error (WeatherInfo *info)
655{
656 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
657 return info->network_error;
658}
659
660void
661weather_info_to_metric (WeatherInfo *info)
662{
663 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)
;
664
665 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
666 info->speed_unit = SPEED_UNIT_MS;
667 info->pressure_unit = PRESSURE_UNIT_HPA;
668 info->distance_unit = DISTANCE_UNIT_METERS;
669}
670
671void
672weather_info_to_imperial (WeatherInfo *info)
673{
674 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)
;
675
676 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
677 info->speed_unit = SPEED_UNIT_MPH;
678 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
679 info->distance_unit = DISTANCE_UNIT_MILES;
680}
681
682const WeatherLocation *
683weather_info_get_location (WeatherInfo *info)
684{
685 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
686 return info->location;
687}
688
689const gchar *
690weather_info_get_location_name (WeatherInfo *info)
691{
692 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
693 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)
;
694 return info->location->name;
695}
696
697const gchar *
698weather_info_get_update (WeatherInfo *info)
699{
700 static gchar buf[200];
701 char *utf8, *timeformat;
702
703 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
704
705 if (!info->valid)
706 return "-";
707
708 if (info->update != 0) {
709 struct tm tm;
710 localtime_r (&info->update, &tm);
711 /* Translators: this is a format string for strftime
712 * see `man 3 strftime` for more details
713 */
714 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
715 NULL((void*)0), NULL((void*)0), NULL((void*)0));
716 if (!timeformat) {
717 strcpy (buf, "???");
718 }
719 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
720 strcpy (buf, "???");
721 }
722 g_free (timeformat);
723
724 /* Convert to UTF-8 */
725 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
726 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
727 g_free (utf8);
728 } else {
729 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
730 buf[sizeof (buf)-1] = '\0';
731 }
732
733 return buf;
734}
735
736const gchar *
737weather_info_get_sky (WeatherInfo *info)
738{
739 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
740 if (!info->valid)
741 return "-";
742 if (info->sky < 0)
743 return _("Unknown")(mateweather_gettext ("Unknown"));
744 return weather_sky_string (info->sky);
745}
746
747const gchar *
748weather_info_get_conditions (WeatherInfo *info)
749{
750 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
751 if (!info->valid)
752 return "-";
753 return weather_conditions_string (info->cond);
754}
755
756static const gchar *
757temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
758{
759 static gchar buf[100];
760
761 switch (to_unit) {
762 case TEMP_UNIT_FAHRENHEIT:
763 if (!want_round) {
764 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
765 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
766 } else {
767 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
768 gdouble temp_r;
769
770 feclearexcept(range_problem);
771 temp_r = round (temp);
772 if (fetestexcept(range_problem))
773 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
774 else
775 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
776 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
777 }
778 break;
779 case TEMP_UNIT_CENTIGRADE:
780 if (!want_round) {
781 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
782 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)));
783 } else {
784 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
785 gdouble temp_r;
786
787 feclearexcept(range_problem);
788 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
789 if (fetestexcept(range_problem))
790 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
791 else
792 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
793 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
794 }
795 break;
796 case TEMP_UNIT_KELVIN:
797 if (!want_round) {
798 /* Translators: This is the temperature in kelvin */
799 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
800 } else {
801 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
802 gdouble temp_r;
803
804 feclearexcept(range_problem);
805 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
806 if (fetestexcept(range_problem))
807 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
808 else
809 /* Translators: This is the temperature in kelvin */
810 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
811 }
812 break;
813
814 case TEMP_UNIT_INVALID:
815 case TEMP_UNIT_DEFAULT:
816 default:
817 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
818 return _("Unknown")(mateweather_gettext ("Unknown"));
819 }
820
821 return buf;
822}
823
824const gchar *
825weather_info_get_temp (WeatherInfo *info)
826{
827 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
828
829 if (!info->valid)
830 return "-";
831 if (info->temp < -500.0)
832 return _("Unknown")(mateweather_gettext ("Unknown"));
833
834 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
835}
836
837const gchar *
838weather_info_get_temp_min (WeatherInfo *info)
839{
840 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
841
842 if (!info->valid || !info->tempMinMaxValid)
843 return "-";
844 if (info->temp_min < -500.0)
845 return _("Unknown")(mateweather_gettext ("Unknown"));
846
847 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
848}
849
850const gchar *
851weather_info_get_temp_max (WeatherInfo *info)
852{
853 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
854
855 if (!info->valid || !info->tempMinMaxValid)
856 return "-";
857 if (info->temp_max < -500.0)
858 return _("Unknown")(mateweather_gettext ("Unknown"));
859
860 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
861}
862
863const gchar *
864weather_info_get_dew (WeatherInfo *info)
865{
866 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
867
868 if (!info->valid)
869 return "-";
870 if (info->dew < -500.0)
871 return _("Unknown")(mateweather_gettext ("Unknown"));
872
873 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
874}
875
876const gchar *
877weather_info_get_humidity (WeatherInfo *info)
878{
879 static gchar buf[20];
880 gdouble humidity;
881
882 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
883
884 if (!info->valid)
885 return "-";
886
887 humidity = calc_humidity (info->temp, info->dew);
888 if (humidity < 0.0)
889 return _("Unknown")(mateweather_gettext ("Unknown"));
890
891 /* Translators: This is the humidity in percent */
892 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
893 return buf;
894}
895
896const gchar *
897weather_info_get_apparent (WeatherInfo *info)
898{
899 gdouble apparent;
900
901 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
902 if (!info->valid)
903 return "-";
904
905 apparent = calc_apparent (info);
906 if (apparent < -500.0)
907 return _("Unknown")(mateweather_gettext ("Unknown"));
908
909 return temperature_string (apparent, info->temperature_unit, FALSE(0));
910}
911
912static const gchar *
913windspeed_string (gfloat knots, SpeedUnit to_unit)
914{
915 static gchar buf[100];
916
917 switch (to_unit) {
918 case SPEED_UNIT_KNOTS:
919 /* Translators: This is the wind speed in knots */
920 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
921 break;
922 case SPEED_UNIT_MPH:
923 /* Translators: This is the wind speed in miles per hour */
924 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
925 break;
926 case SPEED_UNIT_KPH:
927 /* Translators: This is the wind speed in kilometers per hour */
928 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
929 break;
930 case SPEED_UNIT_MS:
931 /* Translators: This is the wind speed in meters per second */
932 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
933 break;
934 case SPEED_UNIT_BFT:
935 /* Translators: This is the wind speed as a Beaufort force factor
936 * (commonly used in nautical wind estimation).
937 */
938 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
939 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
940 break;
941 case SPEED_UNIT_INVALID:
942 case SPEED_UNIT_DEFAULT:
943 default:
944 g_warning ("Conversion to illegal speed unit: %d", to_unit);
945 return _("Unknown")(mateweather_gettext ("Unknown"));
946 }
947
948 return buf;
949}
950
951const gchar *
952weather_info_get_wind (WeatherInfo *info)
953{
954 static gchar buf[200];
955
956 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
957
958 if (!info->valid)
959 return "-";
960 if (info->windspeed < 0.0 || info->wind < 0)
961 return _("Unknown")(mateweather_gettext ("Unknown"));
962 if (info->windspeed == 0.00) {
963 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
964 buf[sizeof (buf)-1] = '\0';
965 } else {
966 /* Translators: This is 'wind direction' / 'wind speed' */
967 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
968 weather_wind_direction_string (info->wind),
969 windspeed_string (info->windspeed, info->speed_unit));
970 }
971 return buf;
972}
973
974const gchar *
975weather_info_get_pressure (WeatherInfo *info)
976{
977 static gchar buf[100];
978
979 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
980
981 if (!info->valid)
982 return "-";
983 if (info->pressure < 0.0)
984 return _("Unknown")(mateweather_gettext ("Unknown"));
985
986 switch (info->pressure_unit) {
987 case PRESSURE_UNIT_INCH_HG:
988 /* Translators: This is pressure in inches of mercury */
989 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
990 break;
991 case PRESSURE_UNIT_MM_HG:
992 /* Translators: This is pressure in millimeters of mercury */
993 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
994 break;
995 case PRESSURE_UNIT_KPA:
996 /* Translators: This is pressure in kiloPascals */
997 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
998 break;
999 case PRESSURE_UNIT_HPA:
1000 /* Translators: This is pressure in hectoPascals */
1001 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1002 break;
1003 case PRESSURE_UNIT_MB:
1004 /* Translators: This is pressure in millibars */
1005 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1006 break;
1007 case PRESSURE_UNIT_ATM:
1008 /* Translators: This is pressure in atmospheres */
1009 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1010 break;
1011
1012 case PRESSURE_UNIT_INVALID:
1013 case PRESSURE_UNIT_DEFAULT:
1014 default:
1015 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1016 return _("Unknown")(mateweather_gettext ("Unknown"));
1017 }
1018
1019 return buf;
1020}
1021
1022const gchar *
1023weather_info_get_visibility (WeatherInfo *info)
1024{
1025 static gchar buf[100];
1026
1027 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1028
1029 if (!info->valid)
1030 return "-";
1031 if (info->visibility < 0.0)
1032 return _("Unknown")(mateweather_gettext ("Unknown"));
1033
1034 switch (info->distance_unit) {
1035 case DISTANCE_UNIT_MILES:
1036 /* Translators: This is the visibility in miles */
1037 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1038 break;
1039 case DISTANCE_UNIT_KM:
1040 /* Translators: This is the visibility in kilometers */
1041 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1042 break;
1043 case DISTANCE_UNIT_METERS:
1044 /* Translators: This is the visibility in meters */
1045 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1046 break;
1047
1048 case DISTANCE_UNIT_INVALID:
1049 case DISTANCE_UNIT_DEFAULT:
1050 default:
1051 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1052 return _("Unknown")(mateweather_gettext ("Unknown"));
1053 }
1054
1055 return buf;
1056}
1057
1058const gchar *
1059weather_info_get_sunrise (WeatherInfo *info)
1060{
1061 static gchar buf[200];
1062 struct tm tm;
1063
1064 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)
;
1065
1066 if (!info->location->latlon_valid)
1067 return "-";
1068 if (!info->valid)
1069 return "-";
1070 if (!calc_sun (info))
1071 return "-";
1072
1073 localtime_r (&info->sunrise, &tm);
1074 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1075 return "-";
1076 return buf;
1077}
1078
1079const gchar *
1080weather_info_get_sunset (WeatherInfo *info)
1081{
1082 static gchar buf[200];
1083 struct tm tm;
1084
1085 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)
;
1086
1087 if (!info->location->latlon_valid)
1088 return "-";
1089 if (!info->valid)
1090 return "-";
1091 if (!calc_sun (info))
1092 return "-";
1093
1094 localtime_r (&info->sunset, &tm);
1095 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1096 return "-";
1097 return buf;
1098}
1099
1100const gchar *
1101weather_info_get_forecast (WeatherInfo *info)
1102{
1103 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1104 return info->forecast;
1105}
1106
1107/**
1108 * weather_info_get_forecast_list:
1109 * Returns list of WeatherInfo* objects for the forecast.
1110 * The list is owned by the 'info' object thus is alive as long
1111 * as the 'info'. This list is filled only when requested with
1112 * type FORECAST_LIST and if available for given location.
1113 * The 'update' property is the date/time when the forecast info
1114 * is used for.
1115 **/
1116GSList *
1117weather_info_get_forecast_list (WeatherInfo *info)
1118{
1119 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1120
1121 if (!info->valid)
1122 return NULL((void*)0);
1123
1124 return info->forecast_list;
1125}
1126
1127GdkPixbufAnimation *
1128weather_info_get_radar (WeatherInfo *info)
1129{
1130 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1131 return info->radar;
1132}
1133
1134const gchar *
1135weather_info_get_temp_summary (WeatherInfo *info)
1136{
1137 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1138
1139 if (!info->valid || info->temp < -500.0)
1140 return "--";
1141
1142 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1143
1144}
1145
1146gchar *
1147weather_info_get_weather_summary (WeatherInfo *info)
1148{
1149 const gchar *buf;
1150
1151 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1152
1153 if (!info->valid)
1154 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1155 buf = weather_info_get_conditions (info);
1156 if (!strcmp (buf, "-"))
1157 buf = weather_info_get_sky (info);
1158 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1159}
1160
1161const gchar *
1162weather_info_get_icon_name (WeatherInfo *info)
1163{
1164 WeatherConditions cond;
1165 WeatherSky sky;
1166 time_t current_time;
1167 gboolean daytime;
1168 gchar* icon;
1169 static gchar icon_buffer[32];
1170 WeatherMoonPhase moonPhase;
1171 WeatherMoonLatitude moonLat;
1172 gint phase;
1173
1174 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1175
1176 if (!info->valid)
1177 return NULL((void*)0);
1178
1179 cond = info->cond;
1180 sky = info->sky;
1181
1182 if (cond.significant) {
1183 if (cond.phenomenon != PHENOMENON_NONE &&
1184 cond.qualifier == QUALIFIER_THUNDERSTORM)
1185 return "weather-storm";
1186
1187 switch (cond.phenomenon) {
1188 case PHENOMENON_INVALID:
1189 case PHENOMENON_LAST:
1190 case PHENOMENON_NONE:
1191 break;
1192
1193 case PHENOMENON_DRIZZLE:
1194 case PHENOMENON_RAIN:
1195 case PHENOMENON_UNKNOWN_PRECIPITATION:
1196 case PHENOMENON_HAIL:
1197 case PHENOMENON_SMALL_HAIL:
1198 return "weather-showers";
1199
1200 case PHENOMENON_SNOW:
1201 case PHENOMENON_SNOW_GRAINS:
1202 case PHENOMENON_ICE_PELLETS:
1203 case PHENOMENON_ICE_CRYSTALS:
1204 return "weather-snow";
1205
1206 case PHENOMENON_TORNADO:
1207 case PHENOMENON_SQUALL:
1208 return "weather-storm";
1209
1210 case PHENOMENON_MIST:
1211 case PHENOMENON_FOG:
1212 case PHENOMENON_SMOKE:
1213 case PHENOMENON_VOLCANIC_ASH:
1214 case PHENOMENON_SAND:
1215 case PHENOMENON_HAZE:
1216 case PHENOMENON_SPRAY:
1217 case PHENOMENON_DUST:
1218 case PHENOMENON_SANDSTORM:
1219 case PHENOMENON_DUSTSTORM:
1220 case PHENOMENON_FUNNEL_CLOUD:
1221 case PHENOMENON_DUST_WHIRLS:
1222 return "weather-fog";
1223 }
1224 }
1225
1226 if (info->midnightSun ||
1227 (!info->sunriseValid && !info->sunsetValid))
1228 daytime = TRUE(!(0));
1229 else if (info->polarNight)
1230 daytime = FALSE(0);
1231 else {
1232 current_time = time (NULL((void*)0));
1233 daytime =
1234 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1235 ( !info->sunsetValid || (current_time < info->sunset) );
1236 }
1237
1238 switch (sky) {
1239 case SKY_INVALID:
1240 case SKY_LAST:
1241 case SKY_CLEAR:
1242 if (daytime)
1243 return "weather-clear";
1244 else {
1245 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1246 break;
1247 }
1248
1249 case SKY_BROKEN:
1250 case SKY_SCATTERED:
1251 case SKY_FEW:
1252 if (daytime)
1253 return "weather-few-clouds";
1254 else {
1255 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1256 break;
1257 }
1258
1259 case SKY_OVERCAST:
1260 return "weather-overcast";
1261
1262 default: /* unrecognized */
1263 return NULL((void*)0);
1264 }
1265
1266 /*
1267 * A phase-of-moon icon is to be returned.
1268 * Determine which one based on the moon's location
1269 */
1270 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1271 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1272 if (phase == MOON_PHASES36) {
1273 phase = 0;
1274 } else if (phase > 0 &&
1275 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1276 < moonLat)) {
1277 /*
1278 * Locations south of the moon's latitude will see the moon in the
1279 * northern sky. The moon waxes and wanes from left to right
1280 * so we reference an icon running in the opposite direction.
1281 */
1282 phase = MOON_PHASES36 - phase;
1283 }
1284
1285 /*
1286 * If the moon is not full then append the angle to the icon string.
1287 * Note that an icon by this name is not required to exist:
1288 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1289 * the full moon image.
1290 */
1291 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1292 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1293 "-%03d", phase * 360 / MOON_PHASES36);
1294 }
1295 }
1296 return icon_buffer;
1297}
1298
1299static gboolean
1300temperature_value (gdouble temp_f,
1301 TempUnit to_unit,
1302 gdouble *value,
1303 TempUnit def_unit)
1304{
1305 gboolean ok = TRUE(!(0));
1306
1307 *value = 0.0;
1308 if (temp_f < -500.0)
1309 return FALSE(0);
1310
1311 if (to_unit == TEMP_UNIT_DEFAULT)
1312 to_unit = def_unit;
1313
1314 switch (to_unit) {
1315 case TEMP_UNIT_FAHRENHEIT:
1316 *value = temp_f;
1317 break;
1318 case TEMP_UNIT_CENTIGRADE:
1319 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1320 break;
1321 case TEMP_UNIT_KELVIN:
1322 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1323 break;
1324 case TEMP_UNIT_INVALID:
1325 case TEMP_UNIT_DEFAULT:
1326 default:
1327 ok = FALSE(0);
1328 break;
1329 }
1330
1331 return ok;
1332}
1333
1334static gboolean
1335speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1336{
1337 gboolean ok = TRUE(!(0));
1338
1339 *value = -1.0;
1340
1341 if (knots < 0.0)
1342 return FALSE(0);
1343
1344 if (to_unit == SPEED_UNIT_DEFAULT)
1345 to_unit = def_unit;
1346
1347 switch (to_unit) {
1348 case SPEED_UNIT_KNOTS:
1349 *value = knots;
1350 break;
1351 case SPEED_UNIT_MPH:
1352 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1353 break;
1354 case SPEED_UNIT_KPH:
1355 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1356 break;
1357 case SPEED_UNIT_MS:
1358 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1359 break;
1360 case SPEED_UNIT_BFT:
1361 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1362 break;
1363 case SPEED_UNIT_INVALID:
1364 case SPEED_UNIT_DEFAULT:
1365 default:
1366 ok = FALSE(0);
1367 break;
1368 }
1369
1370 return ok;
1371}
1372
1373static gboolean
1374pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1375{
1376 gboolean ok = TRUE(!(0));
1377
1378 *value = -1.0;
1379
1380 if (inHg < 0.0)
1381 return FALSE(0);
1382
1383 if (to_unit == PRESSURE_UNIT_DEFAULT)
1384 to_unit = def_unit;
1385
1386 switch (to_unit) {
1387 case PRESSURE_UNIT_INCH_HG:
1388 *value = inHg;
1389 break;
1390 case PRESSURE_UNIT_MM_HG:
1391 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1392 break;
1393 case PRESSURE_UNIT_KPA:
1394 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1395 break;
1396 case PRESSURE_UNIT_HPA:
1397 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1398 break;
1399 case PRESSURE_UNIT_MB:
1400 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1401 break;
1402 case PRESSURE_UNIT_ATM:
1403 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1404 break;
1405 case PRESSURE_UNIT_INVALID:
1406 case PRESSURE_UNIT_DEFAULT:
1407 default:
1408 ok = FALSE(0);
1409 break;
1410 }
1411
1412 return ok;
1413}
1414
1415static gboolean
1416distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1417{
1418 gboolean ok = TRUE(!(0));
1419
1420 *value = -1.0;
1421
1422 if (miles < 0.0)
1423 return FALSE(0);
1424
1425 if (to_unit == DISTANCE_UNIT_DEFAULT)
1426 to_unit = def_unit;
1427
1428 switch (to_unit) {
1429 case DISTANCE_UNIT_MILES:
1430 *value = miles;
1431 break;
1432 case DISTANCE_UNIT_KM:
1433 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1434 break;
1435 case DISTANCE_UNIT_METERS:
1436 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1437 break;
1438 case DISTANCE_UNIT_INVALID:
1439 case DISTANCE_UNIT_DEFAULT:
1440 default:
1441 ok = FALSE(0);
1442 break;
1443 }
1444
1445 return ok;
1446}
1447
1448gboolean
1449weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1450{
1451 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1452 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)
;
1453
1454 if (!info->valid)
1455 return FALSE(0);
1456
1457 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1458 return FALSE(0);
1459
1460 *sky = info->sky;
1461
1462 return TRUE(!(0));
1463}
1464
1465gboolean
1466weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1467{
1468 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1469 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)
;
1470 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)
;
1471
1472 if (!info->valid)
1473 return FALSE(0);
1474
1475 if (!info->cond.significant)
1476 return FALSE(0);
1477
1478 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1479 info->cond.phenomenon < PHENOMENON_LAST &&
1480 info->cond.qualifier > QUALIFIER_INVALID &&
1481 info->cond.qualifier < QUALIFIER_LAST))
1482 return FALSE(0);
1483
1484 *phenomenon = info->cond.phenomenon;
1485 *qualifier = info->cond.qualifier;
1486
1487 return TRUE(!(0));
1488}
1489
1490gboolean
1491weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1492{
1493 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1494 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)
;
1495
1496 if (!info->valid)
1497 return FALSE(0);
1498
1499 return temperature_value (info->temp, unit, value, info->temperature_unit);
1500}
1501
1502gboolean
1503weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1504{
1505 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1506 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)
;
1507
1508 if (!info->valid || !info->tempMinMaxValid)
1509 return FALSE(0);
1510
1511 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1512}
1513
1514gboolean
1515weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1516{
1517 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1518 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)
;
1519
1520 if (!info->valid || !info->tempMinMaxValid)
1521 return FALSE(0);
1522
1523 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1524}
1525
1526gboolean
1527weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1528{
1529 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1530 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)
;
1531
1532 if (!info->valid)
1533 return FALSE(0);
1534
1535 return temperature_value (info->dew, unit, value, info->temperature_unit);
1536}
1537
1538gboolean
1539weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1540{
1541 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1542 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)
;
1543
1544 if (!info->valid)
1545 return FALSE(0);
1546
1547 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1548}
1549
1550gboolean
1551weather_info_get_value_update (WeatherInfo *info, time_t *value)
1552{
1553 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1554 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)
;
1555
1556 if (!info->valid)
1557 return FALSE(0);
1558
1559 *value = info->update;
1560
1561 return TRUE(!(0));
1562}
1563
1564gboolean
1565weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1566{
1567 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1568 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)
;
1569
1570 if (!info->valid || !info->sunriseValid)
1571 return FALSE(0);
1572
1573 *value = info->sunrise;
1574
1575 return TRUE(!(0));
1576}
1577
1578gboolean
1579weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1580{
1581 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1582 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)
;
1583
1584 if (!info->valid || !info->sunsetValid)
1585 return FALSE(0);
1586
1587 *value = info->sunset;
1588
1589 return TRUE(!(0));
1590}
1591
1592gboolean
1593weather_info_get_value_moonphase (WeatherInfo *info,
1594 WeatherMoonPhase *value,
1595 WeatherMoonLatitude *lat)
1596{
1597 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1598 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)
;
1599
1600 if (!info->valid || !info->moonValid)
1601 return FALSE(0);
1602
1603 *value = info->moonphase;
1604 *lat = info->moonlatitude;
1605
1606 return TRUE(!(0));
1607}
1608
1609gboolean
1610weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1611{
1612 gboolean res = FALSE(0);
1613
1614 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1615 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)
;
1616 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)
;
1617
1618 if (!info->valid)
1619 return FALSE(0);
1620
1621 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1622 return FALSE(0);
1623
1624 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1625 *direction = info->wind;
1626
1627 return res;
1628}
1629
1630gboolean
1631weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1632{
1633 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1634 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)
;
1635
1636 if (!info->valid)
1637 return FALSE(0);
1638
1639 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1640}
1641
1642gboolean
1643weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1644{
1645 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1646 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)
;
1647
1648 if (!info->valid)
1649 return FALSE(0);
1650
1651 return distance_value (info->visibility, unit, value, info->distance_unit);
1652}
1653
1654/**
1655 * weather_info_get_upcoming_moonphases:
1656 * @info: WeatherInfo containing the time_t of interest
1657 * @phases: An array of four time_t values that will hold the returned values.
1658 * The values are estimates of the time of the next new, quarter, full and
1659 * three-quarter moons.
1660 *
1661 * Returns: gboolean indicating success or failure
1662 */
1663gboolean
1664weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1665{
1666 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1667 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)
;
1668
1669 return calc_moon_phases(info, phases);
1670}
1671
1672static void
1673_weather_internal_check (void)
1674{
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1676 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"
, 1676, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1677 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", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1678 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", 1678, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1679}
diff --git a/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-d213ed.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-d213ed.html new file mode 100644 index 0000000..52de95c --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-d213ed.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-e31a51.html b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-e31a51.html new file mode 100644 index 0000000..7902405 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/report-e31a51.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-01-223449-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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/scanview.css b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/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/2021-07-01-223449-5793-1@23139abb17f7_libsoup/sorttable.js b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-07-01-223449-5793-1@23139abb17f7_libsoup/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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/1.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/1.html new file mode 100644 index 0000000..ac55286 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/2.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/2.html new file mode 100644 index 0000000..aa1947f --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/3.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/3.html new file mode 100644 index 0000000..2241486 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/4.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/4.html new file mode 100644 index 0000000..f97ceac --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/5.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/5.html new file mode 100644 index 0000000..266fa8f --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/6.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/6.html new file mode 100644 index 0000000..f91e258 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/7.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/7.html new file mode 100644 index 0000000..929846f --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/8.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/8.html new file mode 100644 index 0000000..4089755 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/8.html @@ -0,0 +1,3569 @@ + + + + + + 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
+1679
/* -*- 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);
+        g_object_set (G_OBJECT (info->session), "ssl-use-system-ca-file", TRUE, NULL);
+    }
+
+    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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/index.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/index.html new file mode 100644 index 0000000..e449070 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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.
701variableScope398styleThe scope of the variable 'utf8' can be reduced.
701variableScope398styleThe scope of the variable 'timeformat' can be reduced.
719unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1074unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1095unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/stats.html b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/style.css b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-07-01-223555-8189-cppcheck@23139abb17f7_libsoup/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/2021-07-06-144654-5799-1@74c7f241a34e_master/index.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/index.html new file mode 100644 index 0000000..888d62f --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@f9dd9f4644f8
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-2.fc34) +
Date:Tue Jul 6 14:46:53 2021
+

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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-0f24ae.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-0f24ae.html new file mode 100644 index 0000000..6dae941 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-0f24ae.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-34fe90.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-34fe90.html new file mode 100644 index 0000000..405d0c0 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-34fe90.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-674ad3.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-674ad3.html new file mode 100644 index 0000000..eacd347 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-674ad3.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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)((__typeof__ (clone->radar)) (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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-73ec36.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-73ec36.html new file mode 100644 index 0000000..4ce1a35 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-73ec36.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-7aa71e.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-7aa71e.html new file mode 100644 index 0000000..aba4958 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-7aa71e.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-91ce4a.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-91ce4a.html new file mode 100644 index 0000000..7c4476d --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-91ce4a.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-98c4b4.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-98c4b4.html new file mode 100644 index 0000000..9882571 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-98c4b4.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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)((__typeof__ (clone->radar)) (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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-9b8544.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-9b8544.html new file mode 100644 index 0000000..cd25f21 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-9b8544.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-c70360.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-c70360.html new file mode 100644 index 0000000..5fa9a91 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-c70360.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/report-e69ea1.html b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-e69ea1.html new file mode 100644 index 0000000..bbac92d --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_master/report-e69ea1.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-144654-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/2021-07-06-144654-5799-1@74c7f241a34e_master/scanview.css b/2021-07-06-144654-5799-1@74c7f241a34e_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_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/2021-07-06-144654-5799-1@74c7f241a34e_master/sorttable.js b/2021-07-06-144654-5799-1@74c7f241a34e_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-07-06-144654-5799-1@74c7f241a34e_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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/1.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/1.html new file mode 100644 index 0000000..ac55286 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/2.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/2.html new file mode 100644 index 0000000..aa1947f --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/3.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/3.html new file mode 100644 index 0000000..2241486 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/4.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/4.html new file mode 100644 index 0000000..f97ceac --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/5.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/5.html new file mode 100644 index 0000000..266fa8f --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/6.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/6.html new file mode 100644 index 0000000..f91e258 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/7.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/7.html new file mode 100644 index 0000000..929846f --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/8.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/8.html new file mode 100644 index 0000000..afc51f3 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/8.html @@ -0,0 +1,3567 @@ + + + + + + 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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/index.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/index.html new file mode 100644 index 0000000..be43540 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/stats.html b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/style.css b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-07-06-144806-3170-cppcheck@74c7f241a34e_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/2021-07-06-151504-5797-1@c7506693d197_libsoup/index.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/index.html new file mode 100644 index 0000000..414cfb7 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@9269cf568eae
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-2.fc34) +
Date:Tue Jul 6 15:15:04 2021
+

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_update7261View 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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-08820c.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-08820c.html new file mode 100644 index 0000000..e15df46 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-08820c.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-0fa174.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-0fa174.html new file mode 100644 index 0000000..36dc90e --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-0fa174.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-1fe28e.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-1fe28e.html new file mode 100644 index 0000000..a4fd9f0 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-1fe28e.html @@ -0,0 +1,2031 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 726, 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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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 g_object_set (G_OBJECT (info->session)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
info->session)), (((GType) ((20) << (2))))))))
, "ssl-use-system-ca-file", TRUE(!(0)), NULL((void*)0));
559 }
560
561 metar_start_open (info);
562 iwin_start_open (info);
563
564 if (prefs->radar) {
565 wx_start_open (info);
566 }
567
568 return info;
569}
570
571void
572weather_info_abort (WeatherInfo *info)
573{
574 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)
;
575
576 if (info->session) {
577 soup_session_abort (info->session);
578 info->requests_pending = 0;
579 }
580}
581
582WeatherInfo *
583weather_info_clone (const WeatherInfo *info)
584{
585 WeatherInfo *clone;
586
587 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
588
589 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; }))
;
590
591
592 /* move everything */
593 memmove (clone, info, sizeof (WeatherInfo));
594
595
596 /* special moves */
597 clone->location = weather_location_clone (info->location);
598 /* This handles null correctly */
599 clone->forecast = g_strdup (info->forecast);
600 clone->radar_url = g_strdup (info->radar_url);
601
602 if (info->forecast_list) {
603 GSList *p;
604
605 clone->forecast_list = NULL((void*)0);
606 for (p = info->forecast_list; p; p = p->next) {
607 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
608 }
609
610 clone->forecast_list = g_slist_reverse (clone->forecast_list);
611 }
612
613 clone->radar = info->radar;
614 if (clone->radar != NULL((void*)0))
615 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
616
617 return clone;
618}
619
620void
621weather_info_free (WeatherInfo *info)
622{
623 if (!info)
624 return;
625
626 weather_info_abort (info);
627 if (info->session)
628 g_object_unref (info->session);
629
630 weather_location_free (info->location);
631 info->location = NULL((void*)0);
632
633 g_free (info->forecast);
634 info->forecast = NULL((void*)0);
635
636 free_forecast_list (info);
637
638 if (info->radar != NULL((void*)0)) {
639 g_object_unref (info->radar);
640 info->radar = NULL((void*)0);
641 }
642
643 g_free (info);
644}
645
646gboolean
647weather_info_is_valid (WeatherInfo *info)
648{
649 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
650 return info->valid;
651}
652
653gboolean
654weather_info_network_error (WeatherInfo *info)
655{
656 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
657 return info->network_error;
658}
659
660void
661weather_info_to_metric (WeatherInfo *info)
662{
663 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)
;
664
665 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
666 info->speed_unit = SPEED_UNIT_MS;
667 info->pressure_unit = PRESSURE_UNIT_HPA;
668 info->distance_unit = DISTANCE_UNIT_METERS;
669}
670
671void
672weather_info_to_imperial (WeatherInfo *info)
673{
674 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)
;
675
676 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
677 info->speed_unit = SPEED_UNIT_MPH;
678 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
679 info->distance_unit = DISTANCE_UNIT_MILES;
680}
681
682const WeatherLocation *
683weather_info_get_location (WeatherInfo *info)
684{
685 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
686 return info->location;
687}
688
689const gchar *
690weather_info_get_location_name (WeatherInfo *info)
691{
692 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
693 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)
;
694 return info->location->name;
695}
696
697const gchar *
698weather_info_get_update (WeatherInfo *info)
699{
700 static gchar buf[200];
701 char *utf8, *timeformat;
702
703 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
704
705 if (!info->valid)
706 return "-";
707
708 if (info->update != 0) {
709 struct tm tm;
710 localtime_r (&info->update, &tm);
711 /* Translators: this is a format string for strftime
712 * see `man 3 strftime` for more details
713 */
714 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
715 NULL((void*)0), NULL((void*)0), NULL((void*)0));
716 if (!timeformat) {
717 strcpy (buf, "???");
718 }
719 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
720 strcpy (buf, "???");
721 }
722 g_free (timeformat);
723
724 /* Convert to UTF-8 */
725 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
726 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
727 g_free (utf8);
728 } else {
729 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
730 buf[sizeof (buf)-1] = '\0';
731 }
732
733 return buf;
734}
735
736const gchar *
737weather_info_get_sky (WeatherInfo *info)
738{
739 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
740 if (!info->valid)
741 return "-";
742 if (info->sky < 0)
743 return _("Unknown")(mateweather_gettext ("Unknown"));
744 return weather_sky_string (info->sky);
745}
746
747const gchar *
748weather_info_get_conditions (WeatherInfo *info)
749{
750 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
751 if (!info->valid)
752 return "-";
753 return weather_conditions_string (info->cond);
754}
755
756static const gchar *
757temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
758{
759 static gchar buf[100];
760
761 switch (to_unit) {
762 case TEMP_UNIT_FAHRENHEIT:
763 if (!want_round) {
764 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
765 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
766 } else {
767 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
768 gdouble temp_r;
769
770 feclearexcept(range_problem);
771 temp_r = round (temp);
772 if (fetestexcept(range_problem))
773 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
774 else
775 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
776 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
777 }
778 break;
779 case TEMP_UNIT_CENTIGRADE:
780 if (!want_round) {
781 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
782 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)));
783 } else {
784 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
785 gdouble temp_r;
786
787 feclearexcept(range_problem);
788 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
789 if (fetestexcept(range_problem))
790 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
791 else
792 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
793 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
794 }
795 break;
796 case TEMP_UNIT_KELVIN:
797 if (!want_round) {
798 /* Translators: This is the temperature in kelvin */
799 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
800 } else {
801 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
802 gdouble temp_r;
803
804 feclearexcept(range_problem);
805 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
806 if (fetestexcept(range_problem))
807 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
808 else
809 /* Translators: This is the temperature in kelvin */
810 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
811 }
812 break;
813
814 case TEMP_UNIT_INVALID:
815 case TEMP_UNIT_DEFAULT:
816 default:
817 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
818 return _("Unknown")(mateweather_gettext ("Unknown"));
819 }
820
821 return buf;
822}
823
824const gchar *
825weather_info_get_temp (WeatherInfo *info)
826{
827 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
828
829 if (!info->valid)
830 return "-";
831 if (info->temp < -500.0)
832 return _("Unknown")(mateweather_gettext ("Unknown"));
833
834 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
835}
836
837const gchar *
838weather_info_get_temp_min (WeatherInfo *info)
839{
840 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
841
842 if (!info->valid || !info->tempMinMaxValid)
843 return "-";
844 if (info->temp_min < -500.0)
845 return _("Unknown")(mateweather_gettext ("Unknown"));
846
847 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
848}
849
850const gchar *
851weather_info_get_temp_max (WeatherInfo *info)
852{
853 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
854
855 if (!info->valid || !info->tempMinMaxValid)
856 return "-";
857 if (info->temp_max < -500.0)
858 return _("Unknown")(mateweather_gettext ("Unknown"));
859
860 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
861}
862
863const gchar *
864weather_info_get_dew (WeatherInfo *info)
865{
866 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
867
868 if (!info->valid)
869 return "-";
870 if (info->dew < -500.0)
871 return _("Unknown")(mateweather_gettext ("Unknown"));
872
873 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
874}
875
876const gchar *
877weather_info_get_humidity (WeatherInfo *info)
878{
879 static gchar buf[20];
880 gdouble humidity;
881
882 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
883
884 if (!info->valid)
885 return "-";
886
887 humidity = calc_humidity (info->temp, info->dew);
888 if (humidity < 0.0)
889 return _("Unknown")(mateweather_gettext ("Unknown"));
890
891 /* Translators: This is the humidity in percent */
892 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
893 return buf;
894}
895
896const gchar *
897weather_info_get_apparent (WeatherInfo *info)
898{
899 gdouble apparent;
900
901 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
902 if (!info->valid)
903 return "-";
904
905 apparent = calc_apparent (info);
906 if (apparent < -500.0)
907 return _("Unknown")(mateweather_gettext ("Unknown"));
908
909 return temperature_string (apparent, info->temperature_unit, FALSE(0));
910}
911
912static const gchar *
913windspeed_string (gfloat knots, SpeedUnit to_unit)
914{
915 static gchar buf[100];
916
917 switch (to_unit) {
918 case SPEED_UNIT_KNOTS:
919 /* Translators: This is the wind speed in knots */
920 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
921 break;
922 case SPEED_UNIT_MPH:
923 /* Translators: This is the wind speed in miles per hour */
924 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
925 break;
926 case SPEED_UNIT_KPH:
927 /* Translators: This is the wind speed in kilometers per hour */
928 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
929 break;
930 case SPEED_UNIT_MS:
931 /* Translators: This is the wind speed in meters per second */
932 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
933 break;
934 case SPEED_UNIT_BFT:
935 /* Translators: This is the wind speed as a Beaufort force factor
936 * (commonly used in nautical wind estimation).
937 */
938 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
939 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
940 break;
941 case SPEED_UNIT_INVALID:
942 case SPEED_UNIT_DEFAULT:
943 default:
944 g_warning ("Conversion to illegal speed unit: %d", to_unit);
945 return _("Unknown")(mateweather_gettext ("Unknown"));
946 }
947
948 return buf;
949}
950
951const gchar *
952weather_info_get_wind (WeatherInfo *info)
953{
954 static gchar buf[200];
955
956 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
957
958 if (!info->valid)
959 return "-";
960 if (info->windspeed < 0.0 || info->wind < 0)
961 return _("Unknown")(mateweather_gettext ("Unknown"));
962 if (info->windspeed == 0.00) {
963 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
964 buf[sizeof (buf)-1] = '\0';
965 } else {
966 /* Translators: This is 'wind direction' / 'wind speed' */
967 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
968 weather_wind_direction_string (info->wind),
969 windspeed_string (info->windspeed, info->speed_unit));
970 }
971 return buf;
972}
973
974const gchar *
975weather_info_get_pressure (WeatherInfo *info)
976{
977 static gchar buf[100];
978
979 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
980
981 if (!info->valid)
982 return "-";
983 if (info->pressure < 0.0)
984 return _("Unknown")(mateweather_gettext ("Unknown"));
985
986 switch (info->pressure_unit) {
987 case PRESSURE_UNIT_INCH_HG:
988 /* Translators: This is pressure in inches of mercury */
989 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
990 break;
991 case PRESSURE_UNIT_MM_HG:
992 /* Translators: This is pressure in millimeters of mercury */
993 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
994 break;
995 case PRESSURE_UNIT_KPA:
996 /* Translators: This is pressure in kiloPascals */
997 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
998 break;
999 case PRESSURE_UNIT_HPA:
1000 /* Translators: This is pressure in hectoPascals */
1001 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1002 break;
1003 case PRESSURE_UNIT_MB:
1004 /* Translators: This is pressure in millibars */
1005 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1006 break;
1007 case PRESSURE_UNIT_ATM:
1008 /* Translators: This is pressure in atmospheres */
1009 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1010 break;
1011
1012 case PRESSURE_UNIT_INVALID:
1013 case PRESSURE_UNIT_DEFAULT:
1014 default:
1015 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1016 return _("Unknown")(mateweather_gettext ("Unknown"));
1017 }
1018
1019 return buf;
1020}
1021
1022const gchar *
1023weather_info_get_visibility (WeatherInfo *info)
1024{
1025 static gchar buf[100];
1026
1027 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1028
1029 if (!info->valid)
1030 return "-";
1031 if (info->visibility < 0.0)
1032 return _("Unknown")(mateweather_gettext ("Unknown"));
1033
1034 switch (info->distance_unit) {
1035 case DISTANCE_UNIT_MILES:
1036 /* Translators: This is the visibility in miles */
1037 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1038 break;
1039 case DISTANCE_UNIT_KM:
1040 /* Translators: This is the visibility in kilometers */
1041 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1042 break;
1043 case DISTANCE_UNIT_METERS:
1044 /* Translators: This is the visibility in meters */
1045 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1046 break;
1047
1048 case DISTANCE_UNIT_INVALID:
1049 case DISTANCE_UNIT_DEFAULT:
1050 default:
1051 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1052 return _("Unknown")(mateweather_gettext ("Unknown"));
1053 }
1054
1055 return buf;
1056}
1057
1058const gchar *
1059weather_info_get_sunrise (WeatherInfo *info)
1060{
1061 static gchar buf[200];
1062 struct tm tm;
1063
1064 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)
;
1065
1066 if (!info->location->latlon_valid)
1067 return "-";
1068 if (!info->valid)
1069 return "-";
1070 if (!calc_sun (info))
1071 return "-";
1072
1073 localtime_r (&info->sunrise, &tm);
1074 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1075 return "-";
1076 return buf;
1077}
1078
1079const gchar *
1080weather_info_get_sunset (WeatherInfo *info)
1081{
1082 static gchar buf[200];
1083 struct tm tm;
1084
1085 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)
;
1086
1087 if (!info->location->latlon_valid)
1088 return "-";
1089 if (!info->valid)
1090 return "-";
1091 if (!calc_sun (info))
1092 return "-";
1093
1094 localtime_r (&info->sunset, &tm);
1095 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1096 return "-";
1097 return buf;
1098}
1099
1100const gchar *
1101weather_info_get_forecast (WeatherInfo *info)
1102{
1103 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1104 return info->forecast;
1105}
1106
1107/**
1108 * weather_info_get_forecast_list:
1109 * Returns list of WeatherInfo* objects for the forecast.
1110 * The list is owned by the 'info' object thus is alive as long
1111 * as the 'info'. This list is filled only when requested with
1112 * type FORECAST_LIST and if available for given location.
1113 * The 'update' property is the date/time when the forecast info
1114 * is used for.
1115 **/
1116GSList *
1117weather_info_get_forecast_list (WeatherInfo *info)
1118{
1119 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1120
1121 if (!info->valid)
1122 return NULL((void*)0);
1123
1124 return info->forecast_list;
1125}
1126
1127GdkPixbufAnimation *
1128weather_info_get_radar (WeatherInfo *info)
1129{
1130 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1131 return info->radar;
1132}
1133
1134const gchar *
1135weather_info_get_temp_summary (WeatherInfo *info)
1136{
1137 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1138
1139 if (!info->valid || info->temp < -500.0)
1140 return "--";
1141
1142 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1143
1144}
1145
1146gchar *
1147weather_info_get_weather_summary (WeatherInfo *info)
1148{
1149 const gchar *buf;
1150
1151 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1152
1153 if (!info->valid)
1154 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1155 buf = weather_info_get_conditions (info);
1156 if (!strcmp (buf, "-"))
1157 buf = weather_info_get_sky (info);
1158 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1159}
1160
1161const gchar *
1162weather_info_get_icon_name (WeatherInfo *info)
1163{
1164 WeatherConditions cond;
1165 WeatherSky sky;
1166 time_t current_time;
1167 gboolean daytime;
1168 gchar* icon;
1169 static gchar icon_buffer[32];
1170 WeatherMoonPhase moonPhase;
1171 WeatherMoonLatitude moonLat;
1172 gint phase;
1173
1174 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1175
1176 if (!info->valid)
1177 return NULL((void*)0);
1178
1179 cond = info->cond;
1180 sky = info->sky;
1181
1182 if (cond.significant) {
1183 if (cond.phenomenon != PHENOMENON_NONE &&
1184 cond.qualifier == QUALIFIER_THUNDERSTORM)
1185 return "weather-storm";
1186
1187 switch (cond.phenomenon) {
1188 case PHENOMENON_INVALID:
1189 case PHENOMENON_LAST:
1190 case PHENOMENON_NONE:
1191 break;
1192
1193 case PHENOMENON_DRIZZLE:
1194 case PHENOMENON_RAIN:
1195 case PHENOMENON_UNKNOWN_PRECIPITATION:
1196 case PHENOMENON_HAIL:
1197 case PHENOMENON_SMALL_HAIL:
1198 return "weather-showers";
1199
1200 case PHENOMENON_SNOW:
1201 case PHENOMENON_SNOW_GRAINS:
1202 case PHENOMENON_ICE_PELLETS:
1203 case PHENOMENON_ICE_CRYSTALS:
1204 return "weather-snow";
1205
1206 case PHENOMENON_TORNADO:
1207 case PHENOMENON_SQUALL:
1208 return "weather-storm";
1209
1210 case PHENOMENON_MIST:
1211 case PHENOMENON_FOG:
1212 case PHENOMENON_SMOKE:
1213 case PHENOMENON_VOLCANIC_ASH:
1214 case PHENOMENON_SAND:
1215 case PHENOMENON_HAZE:
1216 case PHENOMENON_SPRAY:
1217 case PHENOMENON_DUST:
1218 case PHENOMENON_SANDSTORM:
1219 case PHENOMENON_DUSTSTORM:
1220 case PHENOMENON_FUNNEL_CLOUD:
1221 case PHENOMENON_DUST_WHIRLS:
1222 return "weather-fog";
1223 }
1224 }
1225
1226 if (info->midnightSun ||
1227 (!info->sunriseValid && !info->sunsetValid))
1228 daytime = TRUE(!(0));
1229 else if (info->polarNight)
1230 daytime = FALSE(0);
1231 else {
1232 current_time = time (NULL((void*)0));
1233 daytime =
1234 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1235 ( !info->sunsetValid || (current_time < info->sunset) );
1236 }
1237
1238 switch (sky) {
1239 case SKY_INVALID:
1240 case SKY_LAST:
1241 case SKY_CLEAR:
1242 if (daytime)
1243 return "weather-clear";
1244 else {
1245 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1246 break;
1247 }
1248
1249 case SKY_BROKEN:
1250 case SKY_SCATTERED:
1251 case SKY_FEW:
1252 if (daytime)
1253 return "weather-few-clouds";
1254 else {
1255 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1256 break;
1257 }
1258
1259 case SKY_OVERCAST:
1260 return "weather-overcast";
1261
1262 default: /* unrecognized */
1263 return NULL((void*)0);
1264 }
1265
1266 /*
1267 * A phase-of-moon icon is to be returned.
1268 * Determine which one based on the moon's location
1269 */
1270 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1271 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1272 if (phase == MOON_PHASES36) {
1273 phase = 0;
1274 } else if (phase > 0 &&
1275 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1276 < moonLat)) {
1277 /*
1278 * Locations south of the moon's latitude will see the moon in the
1279 * northern sky. The moon waxes and wanes from left to right
1280 * so we reference an icon running in the opposite direction.
1281 */
1282 phase = MOON_PHASES36 - phase;
1283 }
1284
1285 /*
1286 * If the moon is not full then append the angle to the icon string.
1287 * Note that an icon by this name is not required to exist:
1288 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1289 * the full moon image.
1290 */
1291 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1292 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1293 "-%03d", phase * 360 / MOON_PHASES36);
1294 }
1295 }
1296 return icon_buffer;
1297}
1298
1299static gboolean
1300temperature_value (gdouble temp_f,
1301 TempUnit to_unit,
1302 gdouble *value,
1303 TempUnit def_unit)
1304{
1305 gboolean ok = TRUE(!(0));
1306
1307 *value = 0.0;
1308 if (temp_f < -500.0)
1309 return FALSE(0);
1310
1311 if (to_unit == TEMP_UNIT_DEFAULT)
1312 to_unit = def_unit;
1313
1314 switch (to_unit) {
1315 case TEMP_UNIT_FAHRENHEIT:
1316 *value = temp_f;
1317 break;
1318 case TEMP_UNIT_CENTIGRADE:
1319 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1320 break;
1321 case TEMP_UNIT_KELVIN:
1322 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1323 break;
1324 case TEMP_UNIT_INVALID:
1325 case TEMP_UNIT_DEFAULT:
1326 default:
1327 ok = FALSE(0);
1328 break;
1329 }
1330
1331 return ok;
1332}
1333
1334static gboolean
1335speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1336{
1337 gboolean ok = TRUE(!(0));
1338
1339 *value = -1.0;
1340
1341 if (knots < 0.0)
1342 return FALSE(0);
1343
1344 if (to_unit == SPEED_UNIT_DEFAULT)
1345 to_unit = def_unit;
1346
1347 switch (to_unit) {
1348 case SPEED_UNIT_KNOTS:
1349 *value = knots;
1350 break;
1351 case SPEED_UNIT_MPH:
1352 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1353 break;
1354 case SPEED_UNIT_KPH:
1355 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1356 break;
1357 case SPEED_UNIT_MS:
1358 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1359 break;
1360 case SPEED_UNIT_BFT:
1361 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1362 break;
1363 case SPEED_UNIT_INVALID:
1364 case SPEED_UNIT_DEFAULT:
1365 default:
1366 ok = FALSE(0);
1367 break;
1368 }
1369
1370 return ok;
1371}
1372
1373static gboolean
1374pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1375{
1376 gboolean ok = TRUE(!(0));
1377
1378 *value = -1.0;
1379
1380 if (inHg < 0.0)
1381 return FALSE(0);
1382
1383 if (to_unit == PRESSURE_UNIT_DEFAULT)
1384 to_unit = def_unit;
1385
1386 switch (to_unit) {
1387 case PRESSURE_UNIT_INCH_HG:
1388 *value = inHg;
1389 break;
1390 case PRESSURE_UNIT_MM_HG:
1391 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1392 break;
1393 case PRESSURE_UNIT_KPA:
1394 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1395 break;
1396 case PRESSURE_UNIT_HPA:
1397 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1398 break;
1399 case PRESSURE_UNIT_MB:
1400 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1401 break;
1402 case PRESSURE_UNIT_ATM:
1403 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1404 break;
1405 case PRESSURE_UNIT_INVALID:
1406 case PRESSURE_UNIT_DEFAULT:
1407 default:
1408 ok = FALSE(0);
1409 break;
1410 }
1411
1412 return ok;
1413}
1414
1415static gboolean
1416distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1417{
1418 gboolean ok = TRUE(!(0));
1419
1420 *value = -1.0;
1421
1422 if (miles < 0.0)
1423 return FALSE(0);
1424
1425 if (to_unit == DISTANCE_UNIT_DEFAULT)
1426 to_unit = def_unit;
1427
1428 switch (to_unit) {
1429 case DISTANCE_UNIT_MILES:
1430 *value = miles;
1431 break;
1432 case DISTANCE_UNIT_KM:
1433 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1434 break;
1435 case DISTANCE_UNIT_METERS:
1436 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1437 break;
1438 case DISTANCE_UNIT_INVALID:
1439 case DISTANCE_UNIT_DEFAULT:
1440 default:
1441 ok = FALSE(0);
1442 break;
1443 }
1444
1445 return ok;
1446}
1447
1448gboolean
1449weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1450{
1451 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1452 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)
;
1453
1454 if (!info->valid)
1455 return FALSE(0);
1456
1457 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1458 return FALSE(0);
1459
1460 *sky = info->sky;
1461
1462 return TRUE(!(0));
1463}
1464
1465gboolean
1466weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1467{
1468 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1469 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)
;
1470 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)
;
1471
1472 if (!info->valid)
1473 return FALSE(0);
1474
1475 if (!info->cond.significant)
1476 return FALSE(0);
1477
1478 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1479 info->cond.phenomenon < PHENOMENON_LAST &&
1480 info->cond.qualifier > QUALIFIER_INVALID &&
1481 info->cond.qualifier < QUALIFIER_LAST))
1482 return FALSE(0);
1483
1484 *phenomenon = info->cond.phenomenon;
1485 *qualifier = info->cond.qualifier;
1486
1487 return TRUE(!(0));
1488}
1489
1490gboolean
1491weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1492{
1493 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1494 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)
;
1495
1496 if (!info->valid)
1497 return FALSE(0);
1498
1499 return temperature_value (info->temp, unit, value, info->temperature_unit);
1500}
1501
1502gboolean
1503weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1504{
1505 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1506 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)
;
1507
1508 if (!info->valid || !info->tempMinMaxValid)
1509 return FALSE(0);
1510
1511 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1512}
1513
1514gboolean
1515weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1516{
1517 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1518 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)
;
1519
1520 if (!info->valid || !info->tempMinMaxValid)
1521 return FALSE(0);
1522
1523 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1524}
1525
1526gboolean
1527weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1528{
1529 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1530 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)
;
1531
1532 if (!info->valid)
1533 return FALSE(0);
1534
1535 return temperature_value (info->dew, unit, value, info->temperature_unit);
1536}
1537
1538gboolean
1539weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1540{
1541 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1542 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)
;
1543
1544 if (!info->valid)
1545 return FALSE(0);
1546
1547 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1548}
1549
1550gboolean
1551weather_info_get_value_update (WeatherInfo *info, time_t *value)
1552{
1553 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1554 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)
;
1555
1556 if (!info->valid)
1557 return FALSE(0);
1558
1559 *value = info->update;
1560
1561 return TRUE(!(0));
1562}
1563
1564gboolean
1565weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1566{
1567 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1568 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)
;
1569
1570 if (!info->valid || !info->sunriseValid)
1571 return FALSE(0);
1572
1573 *value = info->sunrise;
1574
1575 return TRUE(!(0));
1576}
1577
1578gboolean
1579weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1580{
1581 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1582 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)
;
1583
1584 if (!info->valid || !info->sunsetValid)
1585 return FALSE(0);
1586
1587 *value = info->sunset;
1588
1589 return TRUE(!(0));
1590}
1591
1592gboolean
1593weather_info_get_value_moonphase (WeatherInfo *info,
1594 WeatherMoonPhase *value,
1595 WeatherMoonLatitude *lat)
1596{
1597 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1598 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)
;
1599
1600 if (!info->valid || !info->moonValid)
1601 return FALSE(0);
1602
1603 *value = info->moonphase;
1604 *lat = info->moonlatitude;
1605
1606 return TRUE(!(0));
1607}
1608
1609gboolean
1610weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1611{
1612 gboolean res = FALSE(0);
1613
1614 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1615 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)
;
1616 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)
;
1617
1618 if (!info->valid)
1619 return FALSE(0);
1620
1621 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1622 return FALSE(0);
1623
1624 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1625 *direction = info->wind;
1626
1627 return res;
1628}
1629
1630gboolean
1631weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1632{
1633 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1634 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)
;
1635
1636 if (!info->valid)
1637 return FALSE(0);
1638
1639 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1640}
1641
1642gboolean
1643weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1644{
1645 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1646 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)
;
1647
1648 if (!info->valid)
1649 return FALSE(0);
1650
1651 return distance_value (info->visibility, unit, value, info->distance_unit);
1652}
1653
1654/**
1655 * weather_info_get_upcoming_moonphases:
1656 * @info: WeatherInfo containing the time_t of interest
1657 * @phases: An array of four time_t values that will hold the returned values.
1658 * The values are estimates of the time of the next new, quarter, full and
1659 * three-quarter moons.
1660 *
1661 * Returns: gboolean indicating success or failure
1662 */
1663gboolean
1664weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1665{
1666 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1667 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)
;
1668
1669 return calc_moon_phases(info, phases);
1670}
1671
1672static void
1673_weather_internal_check (void)
1674{
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1676 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"
, 1676, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1677 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", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1678 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", 1678, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1679}
diff --git a/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-7ede98.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-7ede98.html new file mode 100644 index 0000000..6e110b0 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-7ede98.html @@ -0,0 +1,2031 @@ + + + +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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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 g_object_set (G_OBJECT (info->session)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
info->session)), (((GType) ((20) << (2))))))))
, "ssl-use-system-ca-file", TRUE(!(0)), NULL((void*)0));
559 }
560
561 metar_start_open (info);
562 iwin_start_open (info);
563
564 if (prefs->radar) {
565 wx_start_open (info);
566 }
567
568 return info;
569}
570
571void
572weather_info_abort (WeatherInfo *info)
573{
574 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)
;
575
576 if (info->session) {
577 soup_session_abort (info->session);
578 info->requests_pending = 0;
579 }
580}
581
582WeatherInfo *
583weather_info_clone (const WeatherInfo *info)
584{
585 WeatherInfo *clone;
586
587 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
588
589 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; }))
;
590
591
592 /* move everything */
593 memmove (clone, info, sizeof (WeatherInfo));
594
595
596 /* special moves */
597 clone->location = weather_location_clone (info->location);
598 /* This handles null correctly */
599 clone->forecast = g_strdup (info->forecast);
600 clone->radar_url = g_strdup (info->radar_url);
601
602 if (info->forecast_list) {
603 GSList *p;
604
605 clone->forecast_list = NULL((void*)0);
606 for (p = info->forecast_list; p; p = p->next) {
607 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
608 }
609
610 clone->forecast_list = g_slist_reverse (clone->forecast_list);
611 }
612
613 clone->radar = info->radar;
614 if (clone->radar != NULL((void*)0))
615 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
616
617 return clone;
618}
619
620void
621weather_info_free (WeatherInfo *info)
622{
623 if (!info)
624 return;
625
626 weather_info_abort (info);
627 if (info->session)
628 g_object_unref (info->session);
629
630 weather_location_free (info->location);
631 info->location = NULL((void*)0);
632
633 g_free (info->forecast);
634 info->forecast = NULL((void*)0);
635
636 free_forecast_list (info);
637
638 if (info->radar != NULL((void*)0)) {
639 g_object_unref (info->radar);
640 info->radar = NULL((void*)0);
641 }
642
643 g_free (info);
644}
645
646gboolean
647weather_info_is_valid (WeatherInfo *info)
648{
649 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
650 return info->valid;
651}
652
653gboolean
654weather_info_network_error (WeatherInfo *info)
655{
656 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
657 return info->network_error;
658}
659
660void
661weather_info_to_metric (WeatherInfo *info)
662{
663 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)
;
664
665 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
666 info->speed_unit = SPEED_UNIT_MS;
667 info->pressure_unit = PRESSURE_UNIT_HPA;
668 info->distance_unit = DISTANCE_UNIT_METERS;
669}
670
671void
672weather_info_to_imperial (WeatherInfo *info)
673{
674 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)
;
675
676 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
677 info->speed_unit = SPEED_UNIT_MPH;
678 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
679 info->distance_unit = DISTANCE_UNIT_MILES;
680}
681
682const WeatherLocation *
683weather_info_get_location (WeatherInfo *info)
684{
685 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
686 return info->location;
687}
688
689const gchar *
690weather_info_get_location_name (WeatherInfo *info)
691{
692 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
693 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)
;
694 return info->location->name;
695}
696
697const gchar *
698weather_info_get_update (WeatherInfo *info)
699{
700 static gchar buf[200];
701 char *utf8, *timeformat;
702
703 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
704
705 if (!info->valid)
706 return "-";
707
708 if (info->update != 0) {
709 struct tm tm;
710 localtime_r (&info->update, &tm);
711 /* Translators: this is a format string for strftime
712 * see `man 3 strftime` for more details
713 */
714 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
715 NULL((void*)0), NULL((void*)0), NULL((void*)0));
716 if (!timeformat) {
717 strcpy (buf, "???");
718 }
719 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
720 strcpy (buf, "???");
721 }
722 g_free (timeformat);
723
724 /* Convert to UTF-8 */
725 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
726 strcpy (buf, utf8);
727 g_free (utf8);
728 } else {
729 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
730 buf[sizeof (buf)-1] = '\0';
731 }
732
733 return buf;
734}
735
736const gchar *
737weather_info_get_sky (WeatherInfo *info)
738{
739 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
740 if (!info->valid)
741 return "-";
742 if (info->sky < 0)
743 return _("Unknown")(mateweather_gettext ("Unknown"));
744 return weather_sky_string (info->sky);
745}
746
747const gchar *
748weather_info_get_conditions (WeatherInfo *info)
749{
750 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
751 if (!info->valid)
752 return "-";
753 return weather_conditions_string (info->cond);
754}
755
756static const gchar *
757temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
758{
759 static gchar buf[100];
760
761 switch (to_unit) {
762 case TEMP_UNIT_FAHRENHEIT:
763 if (!want_round) {
764 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
765 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
766 } else {
767 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
768 gdouble temp_r;
769
770 feclearexcept(range_problem);
771 temp_r = round (temp);
772 if (fetestexcept(range_problem))
773 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
774 else
775 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
776 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
777 }
778 break;
779 case TEMP_UNIT_CENTIGRADE:
780 if (!want_round) {
781 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
782 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)));
783 } else {
784 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
785 gdouble temp_r;
786
787 feclearexcept(range_problem);
788 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
789 if (fetestexcept(range_problem))
790 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
791 else
792 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
793 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
794 }
795 break;
796 case TEMP_UNIT_KELVIN:
797 if (!want_round) {
798 /* Translators: This is the temperature in kelvin */
799 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
800 } else {
801 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
802 gdouble temp_r;
803
804 feclearexcept(range_problem);
805 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
806 if (fetestexcept(range_problem))
807 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
808 else
809 /* Translators: This is the temperature in kelvin */
810 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
811 }
812 break;
813
814 case TEMP_UNIT_INVALID:
815 case TEMP_UNIT_DEFAULT:
816 default:
817 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
818 return _("Unknown")(mateweather_gettext ("Unknown"));
819 }
820
821 return buf;
822}
823
824const gchar *
825weather_info_get_temp (WeatherInfo *info)
826{
827 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
828
829 if (!info->valid)
830 return "-";
831 if (info->temp < -500.0)
832 return _("Unknown")(mateweather_gettext ("Unknown"));
833
834 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
835}
836
837const gchar *
838weather_info_get_temp_min (WeatherInfo *info)
839{
840 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
841
842 if (!info->valid || !info->tempMinMaxValid)
843 return "-";
844 if (info->temp_min < -500.0)
845 return _("Unknown")(mateweather_gettext ("Unknown"));
846
847 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
848}
849
850const gchar *
851weather_info_get_temp_max (WeatherInfo *info)
852{
853 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
854
855 if (!info->valid || !info->tempMinMaxValid)
856 return "-";
857 if (info->temp_max < -500.0)
858 return _("Unknown")(mateweather_gettext ("Unknown"));
859
860 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
861}
862
863const gchar *
864weather_info_get_dew (WeatherInfo *info)
865{
866 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
867
868 if (!info->valid)
869 return "-";
870 if (info->dew < -500.0)
871 return _("Unknown")(mateweather_gettext ("Unknown"));
872
873 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
874}
875
876const gchar *
877weather_info_get_humidity (WeatherInfo *info)
878{
879 static gchar buf[20];
880 gdouble humidity;
881
882 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
883
884 if (!info->valid)
885 return "-";
886
887 humidity = calc_humidity (info->temp, info->dew);
888 if (humidity < 0.0)
889 return _("Unknown")(mateweather_gettext ("Unknown"));
890
891 /* Translators: This is the humidity in percent */
892 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
893 return buf;
894}
895
896const gchar *
897weather_info_get_apparent (WeatherInfo *info)
898{
899 gdouble apparent;
900
901 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
902 if (!info->valid)
903 return "-";
904
905 apparent = calc_apparent (info);
906 if (apparent < -500.0)
907 return _("Unknown")(mateweather_gettext ("Unknown"));
908
909 return temperature_string (apparent, info->temperature_unit, FALSE(0));
910}
911
912static const gchar *
913windspeed_string (gfloat knots, SpeedUnit to_unit)
914{
915 static gchar buf[100];
916
917 switch (to_unit) {
918 case SPEED_UNIT_KNOTS:
919 /* Translators: This is the wind speed in knots */
920 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
921 break;
922 case SPEED_UNIT_MPH:
923 /* Translators: This is the wind speed in miles per hour */
924 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
925 break;
926 case SPEED_UNIT_KPH:
927 /* Translators: This is the wind speed in kilometers per hour */
928 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
929 break;
930 case SPEED_UNIT_MS:
931 /* Translators: This is the wind speed in meters per second */
932 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
933 break;
934 case SPEED_UNIT_BFT:
935 /* Translators: This is the wind speed as a Beaufort force factor
936 * (commonly used in nautical wind estimation).
937 */
938 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
939 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
940 break;
941 case SPEED_UNIT_INVALID:
942 case SPEED_UNIT_DEFAULT:
943 default:
944 g_warning ("Conversion to illegal speed unit: %d", to_unit);
945 return _("Unknown")(mateweather_gettext ("Unknown"));
946 }
947
948 return buf;
949}
950
951const gchar *
952weather_info_get_wind (WeatherInfo *info)
953{
954 static gchar buf[200];
955
956 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
957
958 if (!info->valid)
959 return "-";
960 if (info->windspeed < 0.0 || info->wind < 0)
961 return _("Unknown")(mateweather_gettext ("Unknown"));
962 if (info->windspeed == 0.00) {
963 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
964 buf[sizeof (buf)-1] = '\0';
965 } else {
966 /* Translators: This is 'wind direction' / 'wind speed' */
967 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
968 weather_wind_direction_string (info->wind),
969 windspeed_string (info->windspeed, info->speed_unit));
970 }
971 return buf;
972}
973
974const gchar *
975weather_info_get_pressure (WeatherInfo *info)
976{
977 static gchar buf[100];
978
979 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
980
981 if (!info->valid)
982 return "-";
983 if (info->pressure < 0.0)
984 return _("Unknown")(mateweather_gettext ("Unknown"));
985
986 switch (info->pressure_unit) {
987 case PRESSURE_UNIT_INCH_HG:
988 /* Translators: This is pressure in inches of mercury */
989 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
990 break;
991 case PRESSURE_UNIT_MM_HG:
992 /* Translators: This is pressure in millimeters of mercury */
993 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
994 break;
995 case PRESSURE_UNIT_KPA:
996 /* Translators: This is pressure in kiloPascals */
997 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
998 break;
999 case PRESSURE_UNIT_HPA:
1000 /* Translators: This is pressure in hectoPascals */
1001 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1002 break;
1003 case PRESSURE_UNIT_MB:
1004 /* Translators: This is pressure in millibars */
1005 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1006 break;
1007 case PRESSURE_UNIT_ATM:
1008 /* Translators: This is pressure in atmospheres */
1009 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1010 break;
1011
1012 case PRESSURE_UNIT_INVALID:
1013 case PRESSURE_UNIT_DEFAULT:
1014 default:
1015 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1016 return _("Unknown")(mateweather_gettext ("Unknown"));
1017 }
1018
1019 return buf;
1020}
1021
1022const gchar *
1023weather_info_get_visibility (WeatherInfo *info)
1024{
1025 static gchar buf[100];
1026
1027 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1028
1029 if (!info->valid)
1030 return "-";
1031 if (info->visibility < 0.0)
1032 return _("Unknown")(mateweather_gettext ("Unknown"));
1033
1034 switch (info->distance_unit) {
1035 case DISTANCE_UNIT_MILES:
1036 /* Translators: This is the visibility in miles */
1037 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1038 break;
1039 case DISTANCE_UNIT_KM:
1040 /* Translators: This is the visibility in kilometers */
1041 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1042 break;
1043 case DISTANCE_UNIT_METERS:
1044 /* Translators: This is the visibility in meters */
1045 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1046 break;
1047
1048 case DISTANCE_UNIT_INVALID:
1049 case DISTANCE_UNIT_DEFAULT:
1050 default:
1051 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1052 return _("Unknown")(mateweather_gettext ("Unknown"));
1053 }
1054
1055 return buf;
1056}
1057
1058const gchar *
1059weather_info_get_sunrise (WeatherInfo *info)
1060{
1061 static gchar buf[200];
1062 struct tm tm;
1063
1064 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)
;
1065
1066 if (!info->location->latlon_valid)
1067 return "-";
1068 if (!info->valid)
1069 return "-";
1070 if (!calc_sun (info))
1071 return "-";
1072
1073 localtime_r (&info->sunrise, &tm);
1074 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1075 return "-";
1076 return buf;
1077}
1078
1079const gchar *
1080weather_info_get_sunset (WeatherInfo *info)
1081{
1082 static gchar buf[200];
1083 struct tm tm;
1084
1085 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)
;
1086
1087 if (!info->location->latlon_valid)
1088 return "-";
1089 if (!info->valid)
1090 return "-";
1091 if (!calc_sun (info))
1092 return "-";
1093
1094 localtime_r (&info->sunset, &tm);
1095 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1096 return "-";
1097 return buf;
1098}
1099
1100const gchar *
1101weather_info_get_forecast (WeatherInfo *info)
1102{
1103 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1104 return info->forecast;
1105}
1106
1107/**
1108 * weather_info_get_forecast_list:
1109 * Returns list of WeatherInfo* objects for the forecast.
1110 * The list is owned by the 'info' object thus is alive as long
1111 * as the 'info'. This list is filled only when requested with
1112 * type FORECAST_LIST and if available for given location.
1113 * The 'update' property is the date/time when the forecast info
1114 * is used for.
1115 **/
1116GSList *
1117weather_info_get_forecast_list (WeatherInfo *info)
1118{
1119 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1120
1121 if (!info->valid)
1122 return NULL((void*)0);
1123
1124 return info->forecast_list;
1125}
1126
1127GdkPixbufAnimation *
1128weather_info_get_radar (WeatherInfo *info)
1129{
1130 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1131 return info->radar;
1132}
1133
1134const gchar *
1135weather_info_get_temp_summary (WeatherInfo *info)
1136{
1137 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1138
1139 if (!info->valid || info->temp < -500.0)
1140 return "--";
1141
1142 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1143
1144}
1145
1146gchar *
1147weather_info_get_weather_summary (WeatherInfo *info)
1148{
1149 const gchar *buf;
1150
1151 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1152
1153 if (!info->valid)
1154 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1155 buf = weather_info_get_conditions (info);
1156 if (!strcmp (buf, "-"))
1157 buf = weather_info_get_sky (info);
1158 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1159}
1160
1161const gchar *
1162weather_info_get_icon_name (WeatherInfo *info)
1163{
1164 WeatherConditions cond;
1165 WeatherSky sky;
1166 time_t current_time;
1167 gboolean daytime;
1168 gchar* icon;
1169 static gchar icon_buffer[32];
1170 WeatherMoonPhase moonPhase;
1171 WeatherMoonLatitude moonLat;
1172 gint phase;
1173
1174 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1175
1176 if (!info->valid)
1177 return NULL((void*)0);
1178
1179 cond = info->cond;
1180 sky = info->sky;
1181
1182 if (cond.significant) {
1183 if (cond.phenomenon != PHENOMENON_NONE &&
1184 cond.qualifier == QUALIFIER_THUNDERSTORM)
1185 return "weather-storm";
1186
1187 switch (cond.phenomenon) {
1188 case PHENOMENON_INVALID:
1189 case PHENOMENON_LAST:
1190 case PHENOMENON_NONE:
1191 break;
1192
1193 case PHENOMENON_DRIZZLE:
1194 case PHENOMENON_RAIN:
1195 case PHENOMENON_UNKNOWN_PRECIPITATION:
1196 case PHENOMENON_HAIL:
1197 case PHENOMENON_SMALL_HAIL:
1198 return "weather-showers";
1199
1200 case PHENOMENON_SNOW:
1201 case PHENOMENON_SNOW_GRAINS:
1202 case PHENOMENON_ICE_PELLETS:
1203 case PHENOMENON_ICE_CRYSTALS:
1204 return "weather-snow";
1205
1206 case PHENOMENON_TORNADO:
1207 case PHENOMENON_SQUALL:
1208 return "weather-storm";
1209
1210 case PHENOMENON_MIST:
1211 case PHENOMENON_FOG:
1212 case PHENOMENON_SMOKE:
1213 case PHENOMENON_VOLCANIC_ASH:
1214 case PHENOMENON_SAND:
1215 case PHENOMENON_HAZE:
1216 case PHENOMENON_SPRAY:
1217 case PHENOMENON_DUST:
1218 case PHENOMENON_SANDSTORM:
1219 case PHENOMENON_DUSTSTORM:
1220 case PHENOMENON_FUNNEL_CLOUD:
1221 case PHENOMENON_DUST_WHIRLS:
1222 return "weather-fog";
1223 }
1224 }
1225
1226 if (info->midnightSun ||
1227 (!info->sunriseValid && !info->sunsetValid))
1228 daytime = TRUE(!(0));
1229 else if (info->polarNight)
1230 daytime = FALSE(0);
1231 else {
1232 current_time = time (NULL((void*)0));
1233 daytime =
1234 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1235 ( !info->sunsetValid || (current_time < info->sunset) );
1236 }
1237
1238 switch (sky) {
1239 case SKY_INVALID:
1240 case SKY_LAST:
1241 case SKY_CLEAR:
1242 if (daytime)
1243 return "weather-clear";
1244 else {
1245 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1246 break;
1247 }
1248
1249 case SKY_BROKEN:
1250 case SKY_SCATTERED:
1251 case SKY_FEW:
1252 if (daytime)
1253 return "weather-few-clouds";
1254 else {
1255 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1256 break;
1257 }
1258
1259 case SKY_OVERCAST:
1260 return "weather-overcast";
1261
1262 default: /* unrecognized */
1263 return NULL((void*)0);
1264 }
1265
1266 /*
1267 * A phase-of-moon icon is to be returned.
1268 * Determine which one based on the moon's location
1269 */
1270 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1271 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1272 if (phase == MOON_PHASES36) {
1273 phase = 0;
1274 } else if (phase > 0 &&
1275 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1276 < moonLat)) {
1277 /*
1278 * Locations south of the moon's latitude will see the moon in the
1279 * northern sky. The moon waxes and wanes from left to right
1280 * so we reference an icon running in the opposite direction.
1281 */
1282 phase = MOON_PHASES36 - phase;
1283 }
1284
1285 /*
1286 * If the moon is not full then append the angle to the icon string.
1287 * Note that an icon by this name is not required to exist:
1288 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1289 * the full moon image.
1290 */
1291 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1292 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1293 "-%03d", phase * 360 / MOON_PHASES36);
1294 }
1295 }
1296 return icon_buffer;
1297}
1298
1299static gboolean
1300temperature_value (gdouble temp_f,
1301 TempUnit to_unit,
1302 gdouble *value,
1303 TempUnit def_unit)
1304{
1305 gboolean ok = TRUE(!(0));
1306
1307 *value = 0.0;
1308 if (temp_f < -500.0)
1309 return FALSE(0);
1310
1311 if (to_unit == TEMP_UNIT_DEFAULT)
1312 to_unit = def_unit;
1313
1314 switch (to_unit) {
1315 case TEMP_UNIT_FAHRENHEIT:
1316 *value = temp_f;
1317 break;
1318 case TEMP_UNIT_CENTIGRADE:
1319 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1320 break;
1321 case TEMP_UNIT_KELVIN:
1322 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1323 break;
1324 case TEMP_UNIT_INVALID:
1325 case TEMP_UNIT_DEFAULT:
1326 default:
1327 ok = FALSE(0);
1328 break;
1329 }
1330
1331 return ok;
1332}
1333
1334static gboolean
1335speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1336{
1337 gboolean ok = TRUE(!(0));
1338
1339 *value = -1.0;
1340
1341 if (knots < 0.0)
1342 return FALSE(0);
1343
1344 if (to_unit == SPEED_UNIT_DEFAULT)
1345 to_unit = def_unit;
1346
1347 switch (to_unit) {
1348 case SPEED_UNIT_KNOTS:
1349 *value = knots;
1350 break;
1351 case SPEED_UNIT_MPH:
1352 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1353 break;
1354 case SPEED_UNIT_KPH:
1355 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1356 break;
1357 case SPEED_UNIT_MS:
1358 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1359 break;
1360 case SPEED_UNIT_BFT:
1361 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1362 break;
1363 case SPEED_UNIT_INVALID:
1364 case SPEED_UNIT_DEFAULT:
1365 default:
1366 ok = FALSE(0);
1367 break;
1368 }
1369
1370 return ok;
1371}
1372
1373static gboolean
1374pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1375{
1376 gboolean ok = TRUE(!(0));
1377
1378 *value = -1.0;
1379
1380 if (inHg < 0.0)
1381 return FALSE(0);
1382
1383 if (to_unit == PRESSURE_UNIT_DEFAULT)
1384 to_unit = def_unit;
1385
1386 switch (to_unit) {
1387 case PRESSURE_UNIT_INCH_HG:
1388 *value = inHg;
1389 break;
1390 case PRESSURE_UNIT_MM_HG:
1391 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1392 break;
1393 case PRESSURE_UNIT_KPA:
1394 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1395 break;
1396 case PRESSURE_UNIT_HPA:
1397 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1398 break;
1399 case PRESSURE_UNIT_MB:
1400 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1401 break;
1402 case PRESSURE_UNIT_ATM:
1403 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1404 break;
1405 case PRESSURE_UNIT_INVALID:
1406 case PRESSURE_UNIT_DEFAULT:
1407 default:
1408 ok = FALSE(0);
1409 break;
1410 }
1411
1412 return ok;
1413}
1414
1415static gboolean
1416distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1417{
1418 gboolean ok = TRUE(!(0));
1419
1420 *value = -1.0;
1421
1422 if (miles < 0.0)
1423 return FALSE(0);
1424
1425 if (to_unit == DISTANCE_UNIT_DEFAULT)
1426 to_unit = def_unit;
1427
1428 switch (to_unit) {
1429 case DISTANCE_UNIT_MILES:
1430 *value = miles;
1431 break;
1432 case DISTANCE_UNIT_KM:
1433 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1434 break;
1435 case DISTANCE_UNIT_METERS:
1436 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1437 break;
1438 case DISTANCE_UNIT_INVALID:
1439 case DISTANCE_UNIT_DEFAULT:
1440 default:
1441 ok = FALSE(0);
1442 break;
1443 }
1444
1445 return ok;
1446}
1447
1448gboolean
1449weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1450{
1451 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1452 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)
;
1453
1454 if (!info->valid)
1455 return FALSE(0);
1456
1457 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1458 return FALSE(0);
1459
1460 *sky = info->sky;
1461
1462 return TRUE(!(0));
1463}
1464
1465gboolean
1466weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1467{
1468 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1469 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)
;
1470 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)
;
1471
1472 if (!info->valid)
1473 return FALSE(0);
1474
1475 if (!info->cond.significant)
1476 return FALSE(0);
1477
1478 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1479 info->cond.phenomenon < PHENOMENON_LAST &&
1480 info->cond.qualifier > QUALIFIER_INVALID &&
1481 info->cond.qualifier < QUALIFIER_LAST))
1482 return FALSE(0);
1483
1484 *phenomenon = info->cond.phenomenon;
1485 *qualifier = info->cond.qualifier;
1486
1487 return TRUE(!(0));
1488}
1489
1490gboolean
1491weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1492{
1493 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1494 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)
;
1495
1496 if (!info->valid)
1497 return FALSE(0);
1498
1499 return temperature_value (info->temp, unit, value, info->temperature_unit);
1500}
1501
1502gboolean
1503weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1504{
1505 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1506 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)
;
1507
1508 if (!info->valid || !info->tempMinMaxValid)
1509 return FALSE(0);
1510
1511 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1512}
1513
1514gboolean
1515weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1516{
1517 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1518 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)
;
1519
1520 if (!info->valid || !info->tempMinMaxValid)
1521 return FALSE(0);
1522
1523 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1524}
1525
1526gboolean
1527weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1528{
1529 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1530 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)
;
1531
1532 if (!info->valid)
1533 return FALSE(0);
1534
1535 return temperature_value (info->dew, unit, value, info->temperature_unit);
1536}
1537
1538gboolean
1539weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1540{
1541 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1542 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)
;
1543
1544 if (!info->valid)
1545 return FALSE(0);
1546
1547 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1548}
1549
1550gboolean
1551weather_info_get_value_update (WeatherInfo *info, time_t *value)
1552{
1553 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1554 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)
;
1555
1556 if (!info->valid)
1557 return FALSE(0);
1558
1559 *value = info->update;
1560
1561 return TRUE(!(0));
1562}
1563
1564gboolean
1565weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1566{
1567 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1568 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)
;
1569
1570 if (!info->valid || !info->sunriseValid)
1571 return FALSE(0);
1572
1573 *value = info->sunrise;
1574
1575 return TRUE(!(0));
1576}
1577
1578gboolean
1579weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1580{
1581 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1582 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)
;
1583
1584 if (!info->valid || !info->sunsetValid)
1585 return FALSE(0);
1586
1587 *value = info->sunset;
1588
1589 return TRUE(!(0));
1590}
1591
1592gboolean
1593weather_info_get_value_moonphase (WeatherInfo *info,
1594 WeatherMoonPhase *value,
1595 WeatherMoonLatitude *lat)
1596{
1597 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1598 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)
;
1599
1600 if (!info->valid || !info->moonValid)
1601 return FALSE(0);
1602
1603 *value = info->moonphase;
1604 *lat = info->moonlatitude;
1605
1606 return TRUE(!(0));
1607}
1608
1609gboolean
1610weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1611{
1612 gboolean res = FALSE(0);
1613
1614 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1615 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)
;
1616 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)
;
1617
1618 if (!info->valid)
1619 return FALSE(0);
1620
1621 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1622 return FALSE(0);
1623
1624 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1625 *direction = info->wind;
1626
1627 return res;
1628}
1629
1630gboolean
1631weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1632{
1633 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1634 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)
;
1635
1636 if (!info->valid)
1637 return FALSE(0);
1638
1639 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1640}
1641
1642gboolean
1643weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1644{
1645 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1646 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)
;
1647
1648 if (!info->valid)
1649 return FALSE(0);
1650
1651 return distance_value (info->visibility, unit, value, info->distance_unit);
1652}
1653
1654/**
1655 * weather_info_get_upcoming_moonphases:
1656 * @info: WeatherInfo containing the time_t of interest
1657 * @phases: An array of four time_t values that will hold the returned values.
1658 * The values are estimates of the time of the next new, quarter, full and
1659 * three-quarter moons.
1660 *
1661 * Returns: gboolean indicating success or failure
1662 */
1663gboolean
1664weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1665{
1666 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1667 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)
;
1668
1669 return calc_moon_phases(info, phases);
1670}
1671
1672static void
1673_weather_internal_check (void)
1674{
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1676 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"
, 1676, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1677 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", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1678 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", 1678, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1679}
diff --git a/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-8e8304.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-8e8304.html new file mode 100644 index 0000000..d03ca8e --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-8e8304.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-97cae0.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-97cae0.html new file mode 100644 index 0000000..a8018a3 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-97cae0.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-9bb40e.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-9bb40e.html new file mode 100644 index 0000000..3353c93 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-9bb40e.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-a9e237.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-a9e237.html new file mode 100644 index 0000000..bade68e --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-a9e237.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-c5750f.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-c5750f.html new file mode 100644 index 0000000..7941494 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-c5750f.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-db5a47.html b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-db5a47.html new file mode 100644 index 0000000..a1f05b3 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/report-db5a47.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-06-151504-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/2021-07-06-151504-5797-1@c7506693d197_libsoup/scanview.css b/2021-07-06-151504-5797-1@c7506693d197_libsoup/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/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/2021-07-06-151504-5797-1@c7506693d197_libsoup/sorttable.js b/2021-07-06-151504-5797-1@c7506693d197_libsoup/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-07-06-151504-5797-1@c7506693d197_libsoup/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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/1.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/1.html new file mode 100644 index 0000000..ac55286 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/2.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/2.html new file mode 100644 index 0000000..aa1947f --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/3.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/3.html new file mode 100644 index 0000000..2241486 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/4.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/4.html new file mode 100644 index 0000000..f97ceac --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/5.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/5.html new file mode 100644 index 0000000..266fa8f --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/6.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/6.html new file mode 100644 index 0000000..f91e258 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/7.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/7.html new file mode 100644 index 0000000..929846f --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/8.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/8.html new file mode 100644 index 0000000..4089755 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/8.html @@ -0,0 +1,3569 @@ + + + + + + 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
+1679
/* -*- 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);
+        g_object_set (G_OBJECT (info->session), "ssl-use-system-ca-file", TRUE, NULL);
+    }
+
+    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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/index.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/index.html new file mode 100644 index 0000000..e449070 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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.
701variableScope398styleThe scope of the variable 'utf8' can be reduced.
701variableScope398styleThe scope of the variable 'timeformat' can be reduced.
719unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1074unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1095unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/stats.html b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/style.css b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-07-06-151617-0712-cppcheck@c7506693d197_libsoup/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/2021-07-09-125639-5805-1@c018cd4659d9_master/index.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/index.html new file mode 100644 index 0000000..5dd6923 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@d14cae18fc9e
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-2.fc34) +
Date:Fri Jul 9 12:56:38 2021
+

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_update7261View 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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-09e817.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-09e817.html new file mode 100644 index 0000000..dd7be5a --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-09e817.html @@ -0,0 +1,2031 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 726, 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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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 g_object_set (G_OBJECT (info->session)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
info->session)), (((GType) ((20) << (2))))))))
, "ssl-use-system-ca-file", TRUE(!(0)), NULL((void*)0));
559 }
560
561 metar_start_open (info);
562 iwin_start_open (info);
563
564 if (prefs->radar) {
565 wx_start_open (info);
566 }
567
568 return info;
569}
570
571void
572weather_info_abort (WeatherInfo *info)
573{
574 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)
;
575
576 if (info->session) {
577 soup_session_abort (info->session);
578 info->requests_pending = 0;
579 }
580}
581
582WeatherInfo *
583weather_info_clone (const WeatherInfo *info)
584{
585 WeatherInfo *clone;
586
587 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
588
589 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; }))
;
590
591
592 /* move everything */
593 memmove (clone, info, sizeof (WeatherInfo));
594
595
596 /* special moves */
597 clone->location = weather_location_clone (info->location);
598 /* This handles null correctly */
599 clone->forecast = g_strdup (info->forecast);
600 clone->radar_url = g_strdup (info->radar_url);
601
602 if (info->forecast_list) {
603 GSList *p;
604
605 clone->forecast_list = NULL((void*)0);
606 for (p = info->forecast_list; p; p = p->next) {
607 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
608 }
609
610 clone->forecast_list = g_slist_reverse (clone->forecast_list);
611 }
612
613 clone->radar = info->radar;
614 if (clone->radar != NULL((void*)0))
615 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
616
617 return clone;
618}
619
620void
621weather_info_free (WeatherInfo *info)
622{
623 if (!info)
624 return;
625
626 weather_info_abort (info);
627 if (info->session)
628 g_object_unref (info->session);
629
630 weather_location_free (info->location);
631 info->location = NULL((void*)0);
632
633 g_free (info->forecast);
634 info->forecast = NULL((void*)0);
635
636 free_forecast_list (info);
637
638 if (info->radar != NULL((void*)0)) {
639 g_object_unref (info->radar);
640 info->radar = NULL((void*)0);
641 }
642
643 g_free (info);
644}
645
646gboolean
647weather_info_is_valid (WeatherInfo *info)
648{
649 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
650 return info->valid;
651}
652
653gboolean
654weather_info_network_error (WeatherInfo *info)
655{
656 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
657 return info->network_error;
658}
659
660void
661weather_info_to_metric (WeatherInfo *info)
662{
663 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)
;
664
665 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
666 info->speed_unit = SPEED_UNIT_MS;
667 info->pressure_unit = PRESSURE_UNIT_HPA;
668 info->distance_unit = DISTANCE_UNIT_METERS;
669}
670
671void
672weather_info_to_imperial (WeatherInfo *info)
673{
674 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)
;
675
676 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
677 info->speed_unit = SPEED_UNIT_MPH;
678 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
679 info->distance_unit = DISTANCE_UNIT_MILES;
680}
681
682const WeatherLocation *
683weather_info_get_location (WeatherInfo *info)
684{
685 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
686 return info->location;
687}
688
689const gchar *
690weather_info_get_location_name (WeatherInfo *info)
691{
692 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
693 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)
;
694 return info->location->name;
695}
696
697const gchar *
698weather_info_get_update (WeatherInfo *info)
699{
700 static gchar buf[200];
701 char *utf8, *timeformat;
702
703 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
704
705 if (!info->valid)
706 return "-";
707
708 if (info->update != 0) {
709 struct tm tm;
710 localtime_r (&info->update, &tm);
711 /* Translators: this is a format string for strftime
712 * see `man 3 strftime` for more details
713 */
714 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
715 NULL((void*)0), NULL((void*)0), NULL((void*)0));
716 if (!timeformat) {
717 strcpy (buf, "???");
718 }
719 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
720 strcpy (buf, "???");
721 }
722 g_free (timeformat);
723
724 /* Convert to UTF-8 */
725 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
726 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
727 g_free (utf8);
728 } else {
729 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
730 buf[sizeof (buf)-1] = '\0';
731 }
732
733 return buf;
734}
735
736const gchar *
737weather_info_get_sky (WeatherInfo *info)
738{
739 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
740 if (!info->valid)
741 return "-";
742 if (info->sky < 0)
743 return _("Unknown")(mateweather_gettext ("Unknown"));
744 return weather_sky_string (info->sky);
745}
746
747const gchar *
748weather_info_get_conditions (WeatherInfo *info)
749{
750 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
751 if (!info->valid)
752 return "-";
753 return weather_conditions_string (info->cond);
754}
755
756static const gchar *
757temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
758{
759 static gchar buf[100];
760
761 switch (to_unit) {
762 case TEMP_UNIT_FAHRENHEIT:
763 if (!want_round) {
764 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
765 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
766 } else {
767 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
768 gdouble temp_r;
769
770 feclearexcept(range_problem);
771 temp_r = round (temp);
772 if (fetestexcept(range_problem))
773 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
774 else
775 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
776 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
777 }
778 break;
779 case TEMP_UNIT_CENTIGRADE:
780 if (!want_round) {
781 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
782 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)));
783 } else {
784 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
785 gdouble temp_r;
786
787 feclearexcept(range_problem);
788 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
789 if (fetestexcept(range_problem))
790 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
791 else
792 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
793 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
794 }
795 break;
796 case TEMP_UNIT_KELVIN:
797 if (!want_round) {
798 /* Translators: This is the temperature in kelvin */
799 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
800 } else {
801 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
802 gdouble temp_r;
803
804 feclearexcept(range_problem);
805 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
806 if (fetestexcept(range_problem))
807 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
808 else
809 /* Translators: This is the temperature in kelvin */
810 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
811 }
812 break;
813
814 case TEMP_UNIT_INVALID:
815 case TEMP_UNIT_DEFAULT:
816 default:
817 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
818 return _("Unknown")(mateweather_gettext ("Unknown"));
819 }
820
821 return buf;
822}
823
824const gchar *
825weather_info_get_temp (WeatherInfo *info)
826{
827 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
828
829 if (!info->valid)
830 return "-";
831 if (info->temp < -500.0)
832 return _("Unknown")(mateweather_gettext ("Unknown"));
833
834 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
835}
836
837const gchar *
838weather_info_get_temp_min (WeatherInfo *info)
839{
840 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
841
842 if (!info->valid || !info->tempMinMaxValid)
843 return "-";
844 if (info->temp_min < -500.0)
845 return _("Unknown")(mateweather_gettext ("Unknown"));
846
847 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
848}
849
850const gchar *
851weather_info_get_temp_max (WeatherInfo *info)
852{
853 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
854
855 if (!info->valid || !info->tempMinMaxValid)
856 return "-";
857 if (info->temp_max < -500.0)
858 return _("Unknown")(mateweather_gettext ("Unknown"));
859
860 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
861}
862
863const gchar *
864weather_info_get_dew (WeatherInfo *info)
865{
866 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
867
868 if (!info->valid)
869 return "-";
870 if (info->dew < -500.0)
871 return _("Unknown")(mateweather_gettext ("Unknown"));
872
873 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
874}
875
876const gchar *
877weather_info_get_humidity (WeatherInfo *info)
878{
879 static gchar buf[20];
880 gdouble humidity;
881
882 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
883
884 if (!info->valid)
885 return "-";
886
887 humidity = calc_humidity (info->temp, info->dew);
888 if (humidity < 0.0)
889 return _("Unknown")(mateweather_gettext ("Unknown"));
890
891 /* Translators: This is the humidity in percent */
892 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
893 return buf;
894}
895
896const gchar *
897weather_info_get_apparent (WeatherInfo *info)
898{
899 gdouble apparent;
900
901 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
902 if (!info->valid)
903 return "-";
904
905 apparent = calc_apparent (info);
906 if (apparent < -500.0)
907 return _("Unknown")(mateweather_gettext ("Unknown"));
908
909 return temperature_string (apparent, info->temperature_unit, FALSE(0));
910}
911
912static const gchar *
913windspeed_string (gfloat knots, SpeedUnit to_unit)
914{
915 static gchar buf[100];
916
917 switch (to_unit) {
918 case SPEED_UNIT_KNOTS:
919 /* Translators: This is the wind speed in knots */
920 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
921 break;
922 case SPEED_UNIT_MPH:
923 /* Translators: This is the wind speed in miles per hour */
924 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
925 break;
926 case SPEED_UNIT_KPH:
927 /* Translators: This is the wind speed in kilometers per hour */
928 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
929 break;
930 case SPEED_UNIT_MS:
931 /* Translators: This is the wind speed in meters per second */
932 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
933 break;
934 case SPEED_UNIT_BFT:
935 /* Translators: This is the wind speed as a Beaufort force factor
936 * (commonly used in nautical wind estimation).
937 */
938 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
939 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
940 break;
941 case SPEED_UNIT_INVALID:
942 case SPEED_UNIT_DEFAULT:
943 default:
944 g_warning ("Conversion to illegal speed unit: %d", to_unit);
945 return _("Unknown")(mateweather_gettext ("Unknown"));
946 }
947
948 return buf;
949}
950
951const gchar *
952weather_info_get_wind (WeatherInfo *info)
953{
954 static gchar buf[200];
955
956 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
957
958 if (!info->valid)
959 return "-";
960 if (info->windspeed < 0.0 || info->wind < 0)
961 return _("Unknown")(mateweather_gettext ("Unknown"));
962 if (info->windspeed == 0.00) {
963 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
964 buf[sizeof (buf)-1] = '\0';
965 } else {
966 /* Translators: This is 'wind direction' / 'wind speed' */
967 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
968 weather_wind_direction_string (info->wind),
969 windspeed_string (info->windspeed, info->speed_unit));
970 }
971 return buf;
972}
973
974const gchar *
975weather_info_get_pressure (WeatherInfo *info)
976{
977 static gchar buf[100];
978
979 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
980
981 if (!info->valid)
982 return "-";
983 if (info->pressure < 0.0)
984 return _("Unknown")(mateweather_gettext ("Unknown"));
985
986 switch (info->pressure_unit) {
987 case PRESSURE_UNIT_INCH_HG:
988 /* Translators: This is pressure in inches of mercury */
989 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
990 break;
991 case PRESSURE_UNIT_MM_HG:
992 /* Translators: This is pressure in millimeters of mercury */
993 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
994 break;
995 case PRESSURE_UNIT_KPA:
996 /* Translators: This is pressure in kiloPascals */
997 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
998 break;
999 case PRESSURE_UNIT_HPA:
1000 /* Translators: This is pressure in hectoPascals */
1001 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1002 break;
1003 case PRESSURE_UNIT_MB:
1004 /* Translators: This is pressure in millibars */
1005 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1006 break;
1007 case PRESSURE_UNIT_ATM:
1008 /* Translators: This is pressure in atmospheres */
1009 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1010 break;
1011
1012 case PRESSURE_UNIT_INVALID:
1013 case PRESSURE_UNIT_DEFAULT:
1014 default:
1015 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1016 return _("Unknown")(mateweather_gettext ("Unknown"));
1017 }
1018
1019 return buf;
1020}
1021
1022const gchar *
1023weather_info_get_visibility (WeatherInfo *info)
1024{
1025 static gchar buf[100];
1026
1027 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1028
1029 if (!info->valid)
1030 return "-";
1031 if (info->visibility < 0.0)
1032 return _("Unknown")(mateweather_gettext ("Unknown"));
1033
1034 switch (info->distance_unit) {
1035 case DISTANCE_UNIT_MILES:
1036 /* Translators: This is the visibility in miles */
1037 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1038 break;
1039 case DISTANCE_UNIT_KM:
1040 /* Translators: This is the visibility in kilometers */
1041 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1042 break;
1043 case DISTANCE_UNIT_METERS:
1044 /* Translators: This is the visibility in meters */
1045 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1046 break;
1047
1048 case DISTANCE_UNIT_INVALID:
1049 case DISTANCE_UNIT_DEFAULT:
1050 default:
1051 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1052 return _("Unknown")(mateweather_gettext ("Unknown"));
1053 }
1054
1055 return buf;
1056}
1057
1058const gchar *
1059weather_info_get_sunrise (WeatherInfo *info)
1060{
1061 static gchar buf[200];
1062 struct tm tm;
1063
1064 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)
;
1065
1066 if (!info->location->latlon_valid)
1067 return "-";
1068 if (!info->valid)
1069 return "-";
1070 if (!calc_sun (info))
1071 return "-";
1072
1073 localtime_r (&info->sunrise, &tm);
1074 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1075 return "-";
1076 return buf;
1077}
1078
1079const gchar *
1080weather_info_get_sunset (WeatherInfo *info)
1081{
1082 static gchar buf[200];
1083 struct tm tm;
1084
1085 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)
;
1086
1087 if (!info->location->latlon_valid)
1088 return "-";
1089 if (!info->valid)
1090 return "-";
1091 if (!calc_sun (info))
1092 return "-";
1093
1094 localtime_r (&info->sunset, &tm);
1095 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1096 return "-";
1097 return buf;
1098}
1099
1100const gchar *
1101weather_info_get_forecast (WeatherInfo *info)
1102{
1103 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1104 return info->forecast;
1105}
1106
1107/**
1108 * weather_info_get_forecast_list:
1109 * Returns list of WeatherInfo* objects for the forecast.
1110 * The list is owned by the 'info' object thus is alive as long
1111 * as the 'info'. This list is filled only when requested with
1112 * type FORECAST_LIST and if available for given location.
1113 * The 'update' property is the date/time when the forecast info
1114 * is used for.
1115 **/
1116GSList *
1117weather_info_get_forecast_list (WeatherInfo *info)
1118{
1119 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1120
1121 if (!info->valid)
1122 return NULL((void*)0);
1123
1124 return info->forecast_list;
1125}
1126
1127GdkPixbufAnimation *
1128weather_info_get_radar (WeatherInfo *info)
1129{
1130 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1131 return info->radar;
1132}
1133
1134const gchar *
1135weather_info_get_temp_summary (WeatherInfo *info)
1136{
1137 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1138
1139 if (!info->valid || info->temp < -500.0)
1140 return "--";
1141
1142 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1143
1144}
1145
1146gchar *
1147weather_info_get_weather_summary (WeatherInfo *info)
1148{
1149 const gchar *buf;
1150
1151 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1152
1153 if (!info->valid)
1154 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1155 buf = weather_info_get_conditions (info);
1156 if (!strcmp (buf, "-"))
1157 buf = weather_info_get_sky (info);
1158 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1159}
1160
1161const gchar *
1162weather_info_get_icon_name (WeatherInfo *info)
1163{
1164 WeatherConditions cond;
1165 WeatherSky sky;
1166 time_t current_time;
1167 gboolean daytime;
1168 gchar* icon;
1169 static gchar icon_buffer[32];
1170 WeatherMoonPhase moonPhase;
1171 WeatherMoonLatitude moonLat;
1172 gint phase;
1173
1174 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1175
1176 if (!info->valid)
1177 return NULL((void*)0);
1178
1179 cond = info->cond;
1180 sky = info->sky;
1181
1182 if (cond.significant) {
1183 if (cond.phenomenon != PHENOMENON_NONE &&
1184 cond.qualifier == QUALIFIER_THUNDERSTORM)
1185 return "weather-storm";
1186
1187 switch (cond.phenomenon) {
1188 case PHENOMENON_INVALID:
1189 case PHENOMENON_LAST:
1190 case PHENOMENON_NONE:
1191 break;
1192
1193 case PHENOMENON_DRIZZLE:
1194 case PHENOMENON_RAIN:
1195 case PHENOMENON_UNKNOWN_PRECIPITATION:
1196 case PHENOMENON_HAIL:
1197 case PHENOMENON_SMALL_HAIL:
1198 return "weather-showers";
1199
1200 case PHENOMENON_SNOW:
1201 case PHENOMENON_SNOW_GRAINS:
1202 case PHENOMENON_ICE_PELLETS:
1203 case PHENOMENON_ICE_CRYSTALS:
1204 return "weather-snow";
1205
1206 case PHENOMENON_TORNADO:
1207 case PHENOMENON_SQUALL:
1208 return "weather-storm";
1209
1210 case PHENOMENON_MIST:
1211 case PHENOMENON_FOG:
1212 case PHENOMENON_SMOKE:
1213 case PHENOMENON_VOLCANIC_ASH:
1214 case PHENOMENON_SAND:
1215 case PHENOMENON_HAZE:
1216 case PHENOMENON_SPRAY:
1217 case PHENOMENON_DUST:
1218 case PHENOMENON_SANDSTORM:
1219 case PHENOMENON_DUSTSTORM:
1220 case PHENOMENON_FUNNEL_CLOUD:
1221 case PHENOMENON_DUST_WHIRLS:
1222 return "weather-fog";
1223 }
1224 }
1225
1226 if (info->midnightSun ||
1227 (!info->sunriseValid && !info->sunsetValid))
1228 daytime = TRUE(!(0));
1229 else if (info->polarNight)
1230 daytime = FALSE(0);
1231 else {
1232 current_time = time (NULL((void*)0));
1233 daytime =
1234 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1235 ( !info->sunsetValid || (current_time < info->sunset) );
1236 }
1237
1238 switch (sky) {
1239 case SKY_INVALID:
1240 case SKY_LAST:
1241 case SKY_CLEAR:
1242 if (daytime)
1243 return "weather-clear";
1244 else {
1245 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1246 break;
1247 }
1248
1249 case SKY_BROKEN:
1250 case SKY_SCATTERED:
1251 case SKY_FEW:
1252 if (daytime)
1253 return "weather-few-clouds";
1254 else {
1255 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1256 break;
1257 }
1258
1259 case SKY_OVERCAST:
1260 return "weather-overcast";
1261
1262 default: /* unrecognized */
1263 return NULL((void*)0);
1264 }
1265
1266 /*
1267 * A phase-of-moon icon is to be returned.
1268 * Determine which one based on the moon's location
1269 */
1270 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1271 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1272 if (phase == MOON_PHASES36) {
1273 phase = 0;
1274 } else if (phase > 0 &&
1275 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1276 < moonLat)) {
1277 /*
1278 * Locations south of the moon's latitude will see the moon in the
1279 * northern sky. The moon waxes and wanes from left to right
1280 * so we reference an icon running in the opposite direction.
1281 */
1282 phase = MOON_PHASES36 - phase;
1283 }
1284
1285 /*
1286 * If the moon is not full then append the angle to the icon string.
1287 * Note that an icon by this name is not required to exist:
1288 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1289 * the full moon image.
1290 */
1291 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1292 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1293 "-%03d", phase * 360 / MOON_PHASES36);
1294 }
1295 }
1296 return icon_buffer;
1297}
1298
1299static gboolean
1300temperature_value (gdouble temp_f,
1301 TempUnit to_unit,
1302 gdouble *value,
1303 TempUnit def_unit)
1304{
1305 gboolean ok = TRUE(!(0));
1306
1307 *value = 0.0;
1308 if (temp_f < -500.0)
1309 return FALSE(0);
1310
1311 if (to_unit == TEMP_UNIT_DEFAULT)
1312 to_unit = def_unit;
1313
1314 switch (to_unit) {
1315 case TEMP_UNIT_FAHRENHEIT:
1316 *value = temp_f;
1317 break;
1318 case TEMP_UNIT_CENTIGRADE:
1319 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1320 break;
1321 case TEMP_UNIT_KELVIN:
1322 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1323 break;
1324 case TEMP_UNIT_INVALID:
1325 case TEMP_UNIT_DEFAULT:
1326 default:
1327 ok = FALSE(0);
1328 break;
1329 }
1330
1331 return ok;
1332}
1333
1334static gboolean
1335speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1336{
1337 gboolean ok = TRUE(!(0));
1338
1339 *value = -1.0;
1340
1341 if (knots < 0.0)
1342 return FALSE(0);
1343
1344 if (to_unit == SPEED_UNIT_DEFAULT)
1345 to_unit = def_unit;
1346
1347 switch (to_unit) {
1348 case SPEED_UNIT_KNOTS:
1349 *value = knots;
1350 break;
1351 case SPEED_UNIT_MPH:
1352 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1353 break;
1354 case SPEED_UNIT_KPH:
1355 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1356 break;
1357 case SPEED_UNIT_MS:
1358 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1359 break;
1360 case SPEED_UNIT_BFT:
1361 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1362 break;
1363 case SPEED_UNIT_INVALID:
1364 case SPEED_UNIT_DEFAULT:
1365 default:
1366 ok = FALSE(0);
1367 break;
1368 }
1369
1370 return ok;
1371}
1372
1373static gboolean
1374pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1375{
1376 gboolean ok = TRUE(!(0));
1377
1378 *value = -1.0;
1379
1380 if (inHg < 0.0)
1381 return FALSE(0);
1382
1383 if (to_unit == PRESSURE_UNIT_DEFAULT)
1384 to_unit = def_unit;
1385
1386 switch (to_unit) {
1387 case PRESSURE_UNIT_INCH_HG:
1388 *value = inHg;
1389 break;
1390 case PRESSURE_UNIT_MM_HG:
1391 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1392 break;
1393 case PRESSURE_UNIT_KPA:
1394 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1395 break;
1396 case PRESSURE_UNIT_HPA:
1397 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1398 break;
1399 case PRESSURE_UNIT_MB:
1400 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1401 break;
1402 case PRESSURE_UNIT_ATM:
1403 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1404 break;
1405 case PRESSURE_UNIT_INVALID:
1406 case PRESSURE_UNIT_DEFAULT:
1407 default:
1408 ok = FALSE(0);
1409 break;
1410 }
1411
1412 return ok;
1413}
1414
1415static gboolean
1416distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1417{
1418 gboolean ok = TRUE(!(0));
1419
1420 *value = -1.0;
1421
1422 if (miles < 0.0)
1423 return FALSE(0);
1424
1425 if (to_unit == DISTANCE_UNIT_DEFAULT)
1426 to_unit = def_unit;
1427
1428 switch (to_unit) {
1429 case DISTANCE_UNIT_MILES:
1430 *value = miles;
1431 break;
1432 case DISTANCE_UNIT_KM:
1433 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1434 break;
1435 case DISTANCE_UNIT_METERS:
1436 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1437 break;
1438 case DISTANCE_UNIT_INVALID:
1439 case DISTANCE_UNIT_DEFAULT:
1440 default:
1441 ok = FALSE(0);
1442 break;
1443 }
1444
1445 return ok;
1446}
1447
1448gboolean
1449weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1450{
1451 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1452 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)
;
1453
1454 if (!info->valid)
1455 return FALSE(0);
1456
1457 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1458 return FALSE(0);
1459
1460 *sky = info->sky;
1461
1462 return TRUE(!(0));
1463}
1464
1465gboolean
1466weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1467{
1468 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1469 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)
;
1470 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)
;
1471
1472 if (!info->valid)
1473 return FALSE(0);
1474
1475 if (!info->cond.significant)
1476 return FALSE(0);
1477
1478 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1479 info->cond.phenomenon < PHENOMENON_LAST &&
1480 info->cond.qualifier > QUALIFIER_INVALID &&
1481 info->cond.qualifier < QUALIFIER_LAST))
1482 return FALSE(0);
1483
1484 *phenomenon = info->cond.phenomenon;
1485 *qualifier = info->cond.qualifier;
1486
1487 return TRUE(!(0));
1488}
1489
1490gboolean
1491weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1492{
1493 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1494 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)
;
1495
1496 if (!info->valid)
1497 return FALSE(0);
1498
1499 return temperature_value (info->temp, unit, value, info->temperature_unit);
1500}
1501
1502gboolean
1503weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1504{
1505 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1506 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)
;
1507
1508 if (!info->valid || !info->tempMinMaxValid)
1509 return FALSE(0);
1510
1511 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1512}
1513
1514gboolean
1515weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1516{
1517 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1518 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)
;
1519
1520 if (!info->valid || !info->tempMinMaxValid)
1521 return FALSE(0);
1522
1523 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1524}
1525
1526gboolean
1527weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1528{
1529 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1530 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)
;
1531
1532 if (!info->valid)
1533 return FALSE(0);
1534
1535 return temperature_value (info->dew, unit, value, info->temperature_unit);
1536}
1537
1538gboolean
1539weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1540{
1541 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1542 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)
;
1543
1544 if (!info->valid)
1545 return FALSE(0);
1546
1547 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1548}
1549
1550gboolean
1551weather_info_get_value_update (WeatherInfo *info, time_t *value)
1552{
1553 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1554 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)
;
1555
1556 if (!info->valid)
1557 return FALSE(0);
1558
1559 *value = info->update;
1560
1561 return TRUE(!(0));
1562}
1563
1564gboolean
1565weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1566{
1567 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1568 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)
;
1569
1570 if (!info->valid || !info->sunriseValid)
1571 return FALSE(0);
1572
1573 *value = info->sunrise;
1574
1575 return TRUE(!(0));
1576}
1577
1578gboolean
1579weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1580{
1581 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1582 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)
;
1583
1584 if (!info->valid || !info->sunsetValid)
1585 return FALSE(0);
1586
1587 *value = info->sunset;
1588
1589 return TRUE(!(0));
1590}
1591
1592gboolean
1593weather_info_get_value_moonphase (WeatherInfo *info,
1594 WeatherMoonPhase *value,
1595 WeatherMoonLatitude *lat)
1596{
1597 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1598 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)
;
1599
1600 if (!info->valid || !info->moonValid)
1601 return FALSE(0);
1602
1603 *value = info->moonphase;
1604 *lat = info->moonlatitude;
1605
1606 return TRUE(!(0));
1607}
1608
1609gboolean
1610weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1611{
1612 gboolean res = FALSE(0);
1613
1614 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1615 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)
;
1616 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)
;
1617
1618 if (!info->valid)
1619 return FALSE(0);
1620
1621 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1622 return FALSE(0);
1623
1624 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1625 *direction = info->wind;
1626
1627 return res;
1628}
1629
1630gboolean
1631weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1632{
1633 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1634 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)
;
1635
1636 if (!info->valid)
1637 return FALSE(0);
1638
1639 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1640}
1641
1642gboolean
1643weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1644{
1645 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1646 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)
;
1647
1648 if (!info->valid)
1649 return FALSE(0);
1650
1651 return distance_value (info->visibility, unit, value, info->distance_unit);
1652}
1653
1654/**
1655 * weather_info_get_upcoming_moonphases:
1656 * @info: WeatherInfo containing the time_t of interest
1657 * @phases: An array of four time_t values that will hold the returned values.
1658 * The values are estimates of the time of the next new, quarter, full and
1659 * three-quarter moons.
1660 *
1661 * Returns: gboolean indicating success or failure
1662 */
1663gboolean
1664weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1665{
1666 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1667 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)
;
1668
1669 return calc_moon_phases(info, phases);
1670}
1671
1672static void
1673_weather_internal_check (void)
1674{
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1676 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"
, 1676, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1677 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", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1678 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", 1678, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1679}
diff --git a/2021-07-09-125639-5805-1@c018cd4659d9_master/report-210b0e.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-210b0e.html new file mode 100644 index 0000000..11611ee --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-210b0e.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-3a350b.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-3a350b.html new file mode 100644 index 0000000..3746f67 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-3a350b.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-785848.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-785848.html new file mode 100644 index 0000000..3789a92 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-785848.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-a3e0b5.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-a3e0b5.html new file mode 100644 index 0000000..847d7b0 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-a3e0b5.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-a9527a.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-a9527a.html new file mode 100644 index 0000000..6462371 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-a9527a.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-aca8ad.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-aca8ad.html new file mode 100644 index 0000000..6008f88 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-aca8ad.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a049.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a049.html new file mode 100644 index 0000000..323943f --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a049.html @@ -0,0 +1,2031 @@ + + + +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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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 g_object_set (G_OBJECT (info->session)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
info->session)), (((GType) ((20) << (2))))))))
, "ssl-use-system-ca-file", TRUE(!(0)), NULL((void*)0));
559 }
560
561 metar_start_open (info);
562 iwin_start_open (info);
563
564 if (prefs->radar) {
565 wx_start_open (info);
566 }
567
568 return info;
569}
570
571void
572weather_info_abort (WeatherInfo *info)
573{
574 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)
;
575
576 if (info->session) {
577 soup_session_abort (info->session);
578 info->requests_pending = 0;
579 }
580}
581
582WeatherInfo *
583weather_info_clone (const WeatherInfo *info)
584{
585 WeatherInfo *clone;
586
587 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
588
589 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; }))
;
590
591
592 /* move everything */
593 memmove (clone, info, sizeof (WeatherInfo));
594
595
596 /* special moves */
597 clone->location = weather_location_clone (info->location);
598 /* This handles null correctly */
599 clone->forecast = g_strdup (info->forecast);
600 clone->radar_url = g_strdup (info->radar_url);
601
602 if (info->forecast_list) {
603 GSList *p;
604
605 clone->forecast_list = NULL((void*)0);
606 for (p = info->forecast_list; p; p = p->next) {
607 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
608 }
609
610 clone->forecast_list = g_slist_reverse (clone->forecast_list);
611 }
612
613 clone->radar = info->radar;
614 if (clone->radar != NULL((void*)0))
615 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
616
617 return clone;
618}
619
620void
621weather_info_free (WeatherInfo *info)
622{
623 if (!info)
624 return;
625
626 weather_info_abort (info);
627 if (info->session)
628 g_object_unref (info->session);
629
630 weather_location_free (info->location);
631 info->location = NULL((void*)0);
632
633 g_free (info->forecast);
634 info->forecast = NULL((void*)0);
635
636 free_forecast_list (info);
637
638 if (info->radar != NULL((void*)0)) {
639 g_object_unref (info->radar);
640 info->radar = NULL((void*)0);
641 }
642
643 g_free (info);
644}
645
646gboolean
647weather_info_is_valid (WeatherInfo *info)
648{
649 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
650 return info->valid;
651}
652
653gboolean
654weather_info_network_error (WeatherInfo *info)
655{
656 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
657 return info->network_error;
658}
659
660void
661weather_info_to_metric (WeatherInfo *info)
662{
663 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)
;
664
665 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
666 info->speed_unit = SPEED_UNIT_MS;
667 info->pressure_unit = PRESSURE_UNIT_HPA;
668 info->distance_unit = DISTANCE_UNIT_METERS;
669}
670
671void
672weather_info_to_imperial (WeatherInfo *info)
673{
674 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)
;
675
676 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
677 info->speed_unit = SPEED_UNIT_MPH;
678 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
679 info->distance_unit = DISTANCE_UNIT_MILES;
680}
681
682const WeatherLocation *
683weather_info_get_location (WeatherInfo *info)
684{
685 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
686 return info->location;
687}
688
689const gchar *
690weather_info_get_location_name (WeatherInfo *info)
691{
692 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
693 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)
;
694 return info->location->name;
695}
696
697const gchar *
698weather_info_get_update (WeatherInfo *info)
699{
700 static gchar buf[200];
701 char *utf8, *timeformat;
702
703 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
704
705 if (!info->valid)
706 return "-";
707
708 if (info->update != 0) {
709 struct tm tm;
710 localtime_r (&info->update, &tm);
711 /* Translators: this is a format string for strftime
712 * see `man 3 strftime` for more details
713 */
714 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
715 NULL((void*)0), NULL((void*)0), NULL((void*)0));
716 if (!timeformat) {
717 strcpy (buf, "???");
718 }
719 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
720 strcpy (buf, "???");
721 }
722 g_free (timeformat);
723
724 /* Convert to UTF-8 */
725 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
726 strcpy (buf, utf8);
727 g_free (utf8);
728 } else {
729 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
730 buf[sizeof (buf)-1] = '\0';
731 }
732
733 return buf;
734}
735
736const gchar *
737weather_info_get_sky (WeatherInfo *info)
738{
739 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
740 if (!info->valid)
741 return "-";
742 if (info->sky < 0)
743 return _("Unknown")(mateweather_gettext ("Unknown"));
744 return weather_sky_string (info->sky);
745}
746
747const gchar *
748weather_info_get_conditions (WeatherInfo *info)
749{
750 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
751 if (!info->valid)
752 return "-";
753 return weather_conditions_string (info->cond);
754}
755
756static const gchar *
757temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
758{
759 static gchar buf[100];
760
761 switch (to_unit) {
762 case TEMP_UNIT_FAHRENHEIT:
763 if (!want_round) {
764 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
765 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
766 } else {
767 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
768 gdouble temp_r;
769
770 feclearexcept(range_problem);
771 temp_r = round (temp);
772 if (fetestexcept(range_problem))
773 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
774 else
775 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
776 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
777 }
778 break;
779 case TEMP_UNIT_CENTIGRADE:
780 if (!want_round) {
781 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
782 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)));
783 } else {
784 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
785 gdouble temp_r;
786
787 feclearexcept(range_problem);
788 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
789 if (fetestexcept(range_problem))
790 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
791 else
792 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
793 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
794 }
795 break;
796 case TEMP_UNIT_KELVIN:
797 if (!want_round) {
798 /* Translators: This is the temperature in kelvin */
799 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
800 } else {
801 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
802 gdouble temp_r;
803
804 feclearexcept(range_problem);
805 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
806 if (fetestexcept(range_problem))
807 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
808 else
809 /* Translators: This is the temperature in kelvin */
810 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
811 }
812 break;
813
814 case TEMP_UNIT_INVALID:
815 case TEMP_UNIT_DEFAULT:
816 default:
817 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
818 return _("Unknown")(mateweather_gettext ("Unknown"));
819 }
820
821 return buf;
822}
823
824const gchar *
825weather_info_get_temp (WeatherInfo *info)
826{
827 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
828
829 if (!info->valid)
830 return "-";
831 if (info->temp < -500.0)
832 return _("Unknown")(mateweather_gettext ("Unknown"));
833
834 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
835}
836
837const gchar *
838weather_info_get_temp_min (WeatherInfo *info)
839{
840 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
841
842 if (!info->valid || !info->tempMinMaxValid)
843 return "-";
844 if (info->temp_min < -500.0)
845 return _("Unknown")(mateweather_gettext ("Unknown"));
846
847 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
848}
849
850const gchar *
851weather_info_get_temp_max (WeatherInfo *info)
852{
853 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
854
855 if (!info->valid || !info->tempMinMaxValid)
856 return "-";
857 if (info->temp_max < -500.0)
858 return _("Unknown")(mateweather_gettext ("Unknown"));
859
860 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
861}
862
863const gchar *
864weather_info_get_dew (WeatherInfo *info)
865{
866 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
867
868 if (!info->valid)
869 return "-";
870 if (info->dew < -500.0)
871 return _("Unknown")(mateweather_gettext ("Unknown"));
872
873 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
874}
875
876const gchar *
877weather_info_get_humidity (WeatherInfo *info)
878{
879 static gchar buf[20];
880 gdouble humidity;
881
882 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
883
884 if (!info->valid)
885 return "-";
886
887 humidity = calc_humidity (info->temp, info->dew);
888 if (humidity < 0.0)
889 return _("Unknown")(mateweather_gettext ("Unknown"));
890
891 /* Translators: This is the humidity in percent */
892 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
893 return buf;
894}
895
896const gchar *
897weather_info_get_apparent (WeatherInfo *info)
898{
899 gdouble apparent;
900
901 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
902 if (!info->valid)
903 return "-";
904
905 apparent = calc_apparent (info);
906 if (apparent < -500.0)
907 return _("Unknown")(mateweather_gettext ("Unknown"));
908
909 return temperature_string (apparent, info->temperature_unit, FALSE(0));
910}
911
912static const gchar *
913windspeed_string (gfloat knots, SpeedUnit to_unit)
914{
915 static gchar buf[100];
916
917 switch (to_unit) {
918 case SPEED_UNIT_KNOTS:
919 /* Translators: This is the wind speed in knots */
920 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
921 break;
922 case SPEED_UNIT_MPH:
923 /* Translators: This is the wind speed in miles per hour */
924 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
925 break;
926 case SPEED_UNIT_KPH:
927 /* Translators: This is the wind speed in kilometers per hour */
928 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
929 break;
930 case SPEED_UNIT_MS:
931 /* Translators: This is the wind speed in meters per second */
932 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
933 break;
934 case SPEED_UNIT_BFT:
935 /* Translators: This is the wind speed as a Beaufort force factor
936 * (commonly used in nautical wind estimation).
937 */
938 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
939 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
940 break;
941 case SPEED_UNIT_INVALID:
942 case SPEED_UNIT_DEFAULT:
943 default:
944 g_warning ("Conversion to illegal speed unit: %d", to_unit);
945 return _("Unknown")(mateweather_gettext ("Unknown"));
946 }
947
948 return buf;
949}
950
951const gchar *
952weather_info_get_wind (WeatherInfo *info)
953{
954 static gchar buf[200];
955
956 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
957
958 if (!info->valid)
959 return "-";
960 if (info->windspeed < 0.0 || info->wind < 0)
961 return _("Unknown")(mateweather_gettext ("Unknown"));
962 if (info->windspeed == 0.00) {
963 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
964 buf[sizeof (buf)-1] = '\0';
965 } else {
966 /* Translators: This is 'wind direction' / 'wind speed' */
967 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
968 weather_wind_direction_string (info->wind),
969 windspeed_string (info->windspeed, info->speed_unit));
970 }
971 return buf;
972}
973
974const gchar *
975weather_info_get_pressure (WeatherInfo *info)
976{
977 static gchar buf[100];
978
979 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
980
981 if (!info->valid)
982 return "-";
983 if (info->pressure < 0.0)
984 return _("Unknown")(mateweather_gettext ("Unknown"));
985
986 switch (info->pressure_unit) {
987 case PRESSURE_UNIT_INCH_HG:
988 /* Translators: This is pressure in inches of mercury */
989 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
990 break;
991 case PRESSURE_UNIT_MM_HG:
992 /* Translators: This is pressure in millimeters of mercury */
993 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
994 break;
995 case PRESSURE_UNIT_KPA:
996 /* Translators: This is pressure in kiloPascals */
997 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
998 break;
999 case PRESSURE_UNIT_HPA:
1000 /* Translators: This is pressure in hectoPascals */
1001 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1002 break;
1003 case PRESSURE_UNIT_MB:
1004 /* Translators: This is pressure in millibars */
1005 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1006 break;
1007 case PRESSURE_UNIT_ATM:
1008 /* Translators: This is pressure in atmospheres */
1009 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1010 break;
1011
1012 case PRESSURE_UNIT_INVALID:
1013 case PRESSURE_UNIT_DEFAULT:
1014 default:
1015 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1016 return _("Unknown")(mateweather_gettext ("Unknown"));
1017 }
1018
1019 return buf;
1020}
1021
1022const gchar *
1023weather_info_get_visibility (WeatherInfo *info)
1024{
1025 static gchar buf[100];
1026
1027 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1028
1029 if (!info->valid)
1030 return "-";
1031 if (info->visibility < 0.0)
1032 return _("Unknown")(mateweather_gettext ("Unknown"));
1033
1034 switch (info->distance_unit) {
1035 case DISTANCE_UNIT_MILES:
1036 /* Translators: This is the visibility in miles */
1037 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1038 break;
1039 case DISTANCE_UNIT_KM:
1040 /* Translators: This is the visibility in kilometers */
1041 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1042 break;
1043 case DISTANCE_UNIT_METERS:
1044 /* Translators: This is the visibility in meters */
1045 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1046 break;
1047
1048 case DISTANCE_UNIT_INVALID:
1049 case DISTANCE_UNIT_DEFAULT:
1050 default:
1051 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1052 return _("Unknown")(mateweather_gettext ("Unknown"));
1053 }
1054
1055 return buf;
1056}
1057
1058const gchar *
1059weather_info_get_sunrise (WeatherInfo *info)
1060{
1061 static gchar buf[200];
1062 struct tm tm;
1063
1064 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)
;
1065
1066 if (!info->location->latlon_valid)
1067 return "-";
1068 if (!info->valid)
1069 return "-";
1070 if (!calc_sun (info))
1071 return "-";
1072
1073 localtime_r (&info->sunrise, &tm);
1074 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1075 return "-";
1076 return buf;
1077}
1078
1079const gchar *
1080weather_info_get_sunset (WeatherInfo *info)
1081{
1082 static gchar buf[200];
1083 struct tm tm;
1084
1085 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)
;
1086
1087 if (!info->location->latlon_valid)
1088 return "-";
1089 if (!info->valid)
1090 return "-";
1091 if (!calc_sun (info))
1092 return "-";
1093
1094 localtime_r (&info->sunset, &tm);
1095 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1096 return "-";
1097 return buf;
1098}
1099
1100const gchar *
1101weather_info_get_forecast (WeatherInfo *info)
1102{
1103 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1104 return info->forecast;
1105}
1106
1107/**
1108 * weather_info_get_forecast_list:
1109 * Returns list of WeatherInfo* objects for the forecast.
1110 * The list is owned by the 'info' object thus is alive as long
1111 * as the 'info'. This list is filled only when requested with
1112 * type FORECAST_LIST and if available for given location.
1113 * The 'update' property is the date/time when the forecast info
1114 * is used for.
1115 **/
1116GSList *
1117weather_info_get_forecast_list (WeatherInfo *info)
1118{
1119 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1120
1121 if (!info->valid)
1122 return NULL((void*)0);
1123
1124 return info->forecast_list;
1125}
1126
1127GdkPixbufAnimation *
1128weather_info_get_radar (WeatherInfo *info)
1129{
1130 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1131 return info->radar;
1132}
1133
1134const gchar *
1135weather_info_get_temp_summary (WeatherInfo *info)
1136{
1137 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1138
1139 if (!info->valid || info->temp < -500.0)
1140 return "--";
1141
1142 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1143
1144}
1145
1146gchar *
1147weather_info_get_weather_summary (WeatherInfo *info)
1148{
1149 const gchar *buf;
1150
1151 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1152
1153 if (!info->valid)
1154 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1155 buf = weather_info_get_conditions (info);
1156 if (!strcmp (buf, "-"))
1157 buf = weather_info_get_sky (info);
1158 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1159}
1160
1161const gchar *
1162weather_info_get_icon_name (WeatherInfo *info)
1163{
1164 WeatherConditions cond;
1165 WeatherSky sky;
1166 time_t current_time;
1167 gboolean daytime;
1168 gchar* icon;
1169 static gchar icon_buffer[32];
1170 WeatherMoonPhase moonPhase;
1171 WeatherMoonLatitude moonLat;
1172 gint phase;
1173
1174 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1175
1176 if (!info->valid)
1177 return NULL((void*)0);
1178
1179 cond = info->cond;
1180 sky = info->sky;
1181
1182 if (cond.significant) {
1183 if (cond.phenomenon != PHENOMENON_NONE &&
1184 cond.qualifier == QUALIFIER_THUNDERSTORM)
1185 return "weather-storm";
1186
1187 switch (cond.phenomenon) {
1188 case PHENOMENON_INVALID:
1189 case PHENOMENON_LAST:
1190 case PHENOMENON_NONE:
1191 break;
1192
1193 case PHENOMENON_DRIZZLE:
1194 case PHENOMENON_RAIN:
1195 case PHENOMENON_UNKNOWN_PRECIPITATION:
1196 case PHENOMENON_HAIL:
1197 case PHENOMENON_SMALL_HAIL:
1198 return "weather-showers";
1199
1200 case PHENOMENON_SNOW:
1201 case PHENOMENON_SNOW_GRAINS:
1202 case PHENOMENON_ICE_PELLETS:
1203 case PHENOMENON_ICE_CRYSTALS:
1204 return "weather-snow";
1205
1206 case PHENOMENON_TORNADO:
1207 case PHENOMENON_SQUALL:
1208 return "weather-storm";
1209
1210 case PHENOMENON_MIST:
1211 case PHENOMENON_FOG:
1212 case PHENOMENON_SMOKE:
1213 case PHENOMENON_VOLCANIC_ASH:
1214 case PHENOMENON_SAND:
1215 case PHENOMENON_HAZE:
1216 case PHENOMENON_SPRAY:
1217 case PHENOMENON_DUST:
1218 case PHENOMENON_SANDSTORM:
1219 case PHENOMENON_DUSTSTORM:
1220 case PHENOMENON_FUNNEL_CLOUD:
1221 case PHENOMENON_DUST_WHIRLS:
1222 return "weather-fog";
1223 }
1224 }
1225
1226 if (info->midnightSun ||
1227 (!info->sunriseValid && !info->sunsetValid))
1228 daytime = TRUE(!(0));
1229 else if (info->polarNight)
1230 daytime = FALSE(0);
1231 else {
1232 current_time = time (NULL((void*)0));
1233 daytime =
1234 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1235 ( !info->sunsetValid || (current_time < info->sunset) );
1236 }
1237
1238 switch (sky) {
1239 case SKY_INVALID:
1240 case SKY_LAST:
1241 case SKY_CLEAR:
1242 if (daytime)
1243 return "weather-clear";
1244 else {
1245 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1246 break;
1247 }
1248
1249 case SKY_BROKEN:
1250 case SKY_SCATTERED:
1251 case SKY_FEW:
1252 if (daytime)
1253 return "weather-few-clouds";
1254 else {
1255 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1256 break;
1257 }
1258
1259 case SKY_OVERCAST:
1260 return "weather-overcast";
1261
1262 default: /* unrecognized */
1263 return NULL((void*)0);
1264 }
1265
1266 /*
1267 * A phase-of-moon icon is to be returned.
1268 * Determine which one based on the moon's location
1269 */
1270 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1271 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1272 if (phase == MOON_PHASES36) {
1273 phase = 0;
1274 } else if (phase > 0 &&
1275 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1276 < moonLat)) {
1277 /*
1278 * Locations south of the moon's latitude will see the moon in the
1279 * northern sky. The moon waxes and wanes from left to right
1280 * so we reference an icon running in the opposite direction.
1281 */
1282 phase = MOON_PHASES36 - phase;
1283 }
1284
1285 /*
1286 * If the moon is not full then append the angle to the icon string.
1287 * Note that an icon by this name is not required to exist:
1288 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1289 * the full moon image.
1290 */
1291 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1292 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1293 "-%03d", phase * 360 / MOON_PHASES36);
1294 }
1295 }
1296 return icon_buffer;
1297}
1298
1299static gboolean
1300temperature_value (gdouble temp_f,
1301 TempUnit to_unit,
1302 gdouble *value,
1303 TempUnit def_unit)
1304{
1305 gboolean ok = TRUE(!(0));
1306
1307 *value = 0.0;
1308 if (temp_f < -500.0)
1309 return FALSE(0);
1310
1311 if (to_unit == TEMP_UNIT_DEFAULT)
1312 to_unit = def_unit;
1313
1314 switch (to_unit) {
1315 case TEMP_UNIT_FAHRENHEIT:
1316 *value = temp_f;
1317 break;
1318 case TEMP_UNIT_CENTIGRADE:
1319 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1320 break;
1321 case TEMP_UNIT_KELVIN:
1322 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1323 break;
1324 case TEMP_UNIT_INVALID:
1325 case TEMP_UNIT_DEFAULT:
1326 default:
1327 ok = FALSE(0);
1328 break;
1329 }
1330
1331 return ok;
1332}
1333
1334static gboolean
1335speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1336{
1337 gboolean ok = TRUE(!(0));
1338
1339 *value = -1.0;
1340
1341 if (knots < 0.0)
1342 return FALSE(0);
1343
1344 if (to_unit == SPEED_UNIT_DEFAULT)
1345 to_unit = def_unit;
1346
1347 switch (to_unit) {
1348 case SPEED_UNIT_KNOTS:
1349 *value = knots;
1350 break;
1351 case SPEED_UNIT_MPH:
1352 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1353 break;
1354 case SPEED_UNIT_KPH:
1355 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1356 break;
1357 case SPEED_UNIT_MS:
1358 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1359 break;
1360 case SPEED_UNIT_BFT:
1361 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1362 break;
1363 case SPEED_UNIT_INVALID:
1364 case SPEED_UNIT_DEFAULT:
1365 default:
1366 ok = FALSE(0);
1367 break;
1368 }
1369
1370 return ok;
1371}
1372
1373static gboolean
1374pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1375{
1376 gboolean ok = TRUE(!(0));
1377
1378 *value = -1.0;
1379
1380 if (inHg < 0.0)
1381 return FALSE(0);
1382
1383 if (to_unit == PRESSURE_UNIT_DEFAULT)
1384 to_unit = def_unit;
1385
1386 switch (to_unit) {
1387 case PRESSURE_UNIT_INCH_HG:
1388 *value = inHg;
1389 break;
1390 case PRESSURE_UNIT_MM_HG:
1391 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1392 break;
1393 case PRESSURE_UNIT_KPA:
1394 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1395 break;
1396 case PRESSURE_UNIT_HPA:
1397 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1398 break;
1399 case PRESSURE_UNIT_MB:
1400 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1401 break;
1402 case PRESSURE_UNIT_ATM:
1403 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1404 break;
1405 case PRESSURE_UNIT_INVALID:
1406 case PRESSURE_UNIT_DEFAULT:
1407 default:
1408 ok = FALSE(0);
1409 break;
1410 }
1411
1412 return ok;
1413}
1414
1415static gboolean
1416distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1417{
1418 gboolean ok = TRUE(!(0));
1419
1420 *value = -1.0;
1421
1422 if (miles < 0.0)
1423 return FALSE(0);
1424
1425 if (to_unit == DISTANCE_UNIT_DEFAULT)
1426 to_unit = def_unit;
1427
1428 switch (to_unit) {
1429 case DISTANCE_UNIT_MILES:
1430 *value = miles;
1431 break;
1432 case DISTANCE_UNIT_KM:
1433 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1434 break;
1435 case DISTANCE_UNIT_METERS:
1436 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1437 break;
1438 case DISTANCE_UNIT_INVALID:
1439 case DISTANCE_UNIT_DEFAULT:
1440 default:
1441 ok = FALSE(0);
1442 break;
1443 }
1444
1445 return ok;
1446}
1447
1448gboolean
1449weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1450{
1451 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1452 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)
;
1453
1454 if (!info->valid)
1455 return FALSE(0);
1456
1457 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1458 return FALSE(0);
1459
1460 *sky = info->sky;
1461
1462 return TRUE(!(0));
1463}
1464
1465gboolean
1466weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1467{
1468 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1469 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)
;
1470 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)
;
1471
1472 if (!info->valid)
1473 return FALSE(0);
1474
1475 if (!info->cond.significant)
1476 return FALSE(0);
1477
1478 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1479 info->cond.phenomenon < PHENOMENON_LAST &&
1480 info->cond.qualifier > QUALIFIER_INVALID &&
1481 info->cond.qualifier < QUALIFIER_LAST))
1482 return FALSE(0);
1483
1484 *phenomenon = info->cond.phenomenon;
1485 *qualifier = info->cond.qualifier;
1486
1487 return TRUE(!(0));
1488}
1489
1490gboolean
1491weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1492{
1493 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1494 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)
;
1495
1496 if (!info->valid)
1497 return FALSE(0);
1498
1499 return temperature_value (info->temp, unit, value, info->temperature_unit);
1500}
1501
1502gboolean
1503weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1504{
1505 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1506 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)
;
1507
1508 if (!info->valid || !info->tempMinMaxValid)
1509 return FALSE(0);
1510
1511 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1512}
1513
1514gboolean
1515weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1516{
1517 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1518 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)
;
1519
1520 if (!info->valid || !info->tempMinMaxValid)
1521 return FALSE(0);
1522
1523 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1524}
1525
1526gboolean
1527weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1528{
1529 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1530 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)
;
1531
1532 if (!info->valid)
1533 return FALSE(0);
1534
1535 return temperature_value (info->dew, unit, value, info->temperature_unit);
1536}
1537
1538gboolean
1539weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1540{
1541 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1542 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)
;
1543
1544 if (!info->valid)
1545 return FALSE(0);
1546
1547 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1548}
1549
1550gboolean
1551weather_info_get_value_update (WeatherInfo *info, time_t *value)
1552{
1553 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1554 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)
;
1555
1556 if (!info->valid)
1557 return FALSE(0);
1558
1559 *value = info->update;
1560
1561 return TRUE(!(0));
1562}
1563
1564gboolean
1565weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1566{
1567 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1568 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)
;
1569
1570 if (!info->valid || !info->sunriseValid)
1571 return FALSE(0);
1572
1573 *value = info->sunrise;
1574
1575 return TRUE(!(0));
1576}
1577
1578gboolean
1579weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1580{
1581 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1582 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)
;
1583
1584 if (!info->valid || !info->sunsetValid)
1585 return FALSE(0);
1586
1587 *value = info->sunset;
1588
1589 return TRUE(!(0));
1590}
1591
1592gboolean
1593weather_info_get_value_moonphase (WeatherInfo *info,
1594 WeatherMoonPhase *value,
1595 WeatherMoonLatitude *lat)
1596{
1597 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1598 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)
;
1599
1600 if (!info->valid || !info->moonValid)
1601 return FALSE(0);
1602
1603 *value = info->moonphase;
1604 *lat = info->moonlatitude;
1605
1606 return TRUE(!(0));
1607}
1608
1609gboolean
1610weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1611{
1612 gboolean res = FALSE(0);
1613
1614 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1615 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)
;
1616 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)
;
1617
1618 if (!info->valid)
1619 return FALSE(0);
1620
1621 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1622 return FALSE(0);
1623
1624 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1625 *direction = info->wind;
1626
1627 return res;
1628}
1629
1630gboolean
1631weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1632{
1633 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1634 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)
;
1635
1636 if (!info->valid)
1637 return FALSE(0);
1638
1639 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1640}
1641
1642gboolean
1643weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1644{
1645 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1646 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)
;
1647
1648 if (!info->valid)
1649 return FALSE(0);
1650
1651 return distance_value (info->visibility, unit, value, info->distance_unit);
1652}
1653
1654/**
1655 * weather_info_get_upcoming_moonphases:
1656 * @info: WeatherInfo containing the time_t of interest
1657 * @phases: An array of four time_t values that will hold the returned values.
1658 * The values are estimates of the time of the next new, quarter, full and
1659 * three-quarter moons.
1660 *
1661 * Returns: gboolean indicating success or failure
1662 */
1663gboolean
1664weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1665{
1666 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1667 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)
;
1668
1669 return calc_moon_phases(info, phases);
1670}
1671
1672static void
1673_weather_internal_check (void)
1674{
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1676 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"
, 1676, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1677 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", 1677, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1678 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", 1678, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1679}
diff --git a/2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a499.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a499.html new file mode 100644 index 0000000..cc5146b --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-e6a499.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/report-ff6417.html b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-ff6417.html new file mode 100644 index 0000000..0f0a9e5 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_master/report-ff6417.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-07-09-125639-5805-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/2021-07-09-125639-5805-1@c018cd4659d9_master/scanview.css b/2021-07-09-125639-5805-1@c018cd4659d9_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_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/2021-07-09-125639-5805-1@c018cd4659d9_master/sorttable.js b/2021-07-09-125639-5805-1@c018cd4659d9_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-07-09-125639-5805-1@c018cd4659d9_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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/1.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/1.html new file mode 100644 index 0000000..ac55286 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/2.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/2.html new file mode 100644 index 0000000..aa1947f --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/3.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/3.html new file mode 100644 index 0000000..2241486 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/4.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/4.html new file mode 100644 index 0000000..f97ceac --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/5.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/5.html new file mode 100644 index 0000000..266fa8f --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/6.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/6.html new file mode 100644 index 0000000..f91e258 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/7.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/7.html new file mode 100644 index 0000000..929846f --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/8.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/8.html new file mode 100644 index 0000000..4089755 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/8.html @@ -0,0 +1,3569 @@ + + + + + + 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
+1679
/* -*- 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);
+        g_object_set (G_OBJECT (info->session), "ssl-use-system-ca-file", TRUE, NULL);
+    }
+
+    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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/index.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/index.html new file mode 100644 index 0000000..e449070 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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.
701variableScope398styleThe scope of the variable 'utf8' can be reduced.
701variableScope398styleThe scope of the variable 'timeformat' can be reduced.
719unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1074unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1095unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/stats.html b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/stats.html new file mode 100644 index 0000000..8662a70 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/style.css b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_master/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-07-09-125746-6147-cppcheck@c018cd4659d9_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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/index.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/index.html new file mode 100644 index 0000000..e15c2c3 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/index.html @@ -0,0 +1,131 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@d91ef5987031
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 12.0.0 (Fedora 12.0.0-2.fc34) +
Date:Tue Aug 3 19:00:03 2021
+

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_update7241View 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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-276335.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-276335.html new file mode 100644 index 0000000..e485777 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-276335.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-343b66.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-343b66.html new file mode 100644 index 0000000..e642852 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-343b66.html @@ -0,0 +1,2029 @@ + + + +weather.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:weather.c
Warning:line 724, 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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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_new ();
557 }
558
559 metar_start_open (info);
560 iwin_start_open (info);
561
562 if (prefs->radar) {
563 wx_start_open (info);
564 }
565
566 return info;
567}
568
569void
570weather_info_abort (WeatherInfo *info)
571{
572 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)
;
573
574 if (info->session) {
575 soup_session_abort (info->session);
576 info->requests_pending = 0;
577 }
578}
579
580WeatherInfo *
581weather_info_clone (const WeatherInfo *info)
582{
583 WeatherInfo *clone;
584
585 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
586
587 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; }))
;
588
589
590 /* move everything */
591 memmove (clone, info, sizeof (WeatherInfo));
592
593
594 /* special moves */
595 clone->location = weather_location_clone (info->location);
596 /* This handles null correctly */
597 clone->forecast = g_strdup (info->forecast);
598 clone->radar_url = g_strdup (info->radar_url);
599
600 if (info->forecast_list) {
601 GSList *p;
602
603 clone->forecast_list = NULL((void*)0);
604 for (p = info->forecast_list; p; p = p->next) {
605 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
606 }
607
608 clone->forecast_list = g_slist_reverse (clone->forecast_list);
609 }
610
611 clone->radar = info->radar;
612 if (clone->radar != NULL((void*)0))
613 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
614
615 return clone;
616}
617
618void
619weather_info_free (WeatherInfo *info)
620{
621 if (!info)
622 return;
623
624 weather_info_abort (info);
625 if (info->session)
626 g_object_unref (info->session);
627
628 weather_location_free (info->location);
629 info->location = NULL((void*)0);
630
631 g_free (info->forecast);
632 info->forecast = NULL((void*)0);
633
634 free_forecast_list (info);
635
636 if (info->radar != NULL((void*)0)) {
637 g_object_unref (info->radar);
638 info->radar = NULL((void*)0);
639 }
640
641 g_free (info);
642}
643
644gboolean
645weather_info_is_valid (WeatherInfo *info)
646{
647 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
648 return info->valid;
649}
650
651gboolean
652weather_info_network_error (WeatherInfo *info)
653{
654 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
655 return info->network_error;
656}
657
658void
659weather_info_to_metric (WeatherInfo *info)
660{
661 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)
;
662
663 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
664 info->speed_unit = SPEED_UNIT_MS;
665 info->pressure_unit = PRESSURE_UNIT_HPA;
666 info->distance_unit = DISTANCE_UNIT_METERS;
667}
668
669void
670weather_info_to_imperial (WeatherInfo *info)
671{
672 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)
;
673
674 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
675 info->speed_unit = SPEED_UNIT_MPH;
676 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
677 info->distance_unit = DISTANCE_UNIT_MILES;
678}
679
680const WeatherLocation *
681weather_info_get_location (WeatherInfo *info)
682{
683 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
684 return info->location;
685}
686
687const gchar *
688weather_info_get_location_name (WeatherInfo *info)
689{
690 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
691 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)
;
692 return info->location->name;
693}
694
695const gchar *
696weather_info_get_update (WeatherInfo *info)
697{
698 static gchar buf[200];
699 char *utf8, *timeformat;
700
701 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
702
703 if (!info->valid)
704 return "-";
705
706 if (info->update != 0) {
707 struct tm tm;
708 localtime_r (&info->update, &tm);
709 /* Translators: this is a format string for strftime
710 * see `man 3 strftime` for more details
711 */
712 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
713 NULL((void*)0), NULL((void*)0), NULL((void*)0));
714 if (!timeformat) {
715 strcpy (buf, "???");
716 }
717 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
718 strcpy (buf, "???");
719 }
720 g_free (timeformat);
721
722 /* Convert to UTF-8 */
723 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
724 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
725 g_free (utf8);
726 } else {
727 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
728 buf[sizeof (buf)-1] = '\0';
729 }
730
731 return buf;
732}
733
734const gchar *
735weather_info_get_sky (WeatherInfo *info)
736{
737 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
738 if (!info->valid)
739 return "-";
740 if (info->sky < 0)
741 return _("Unknown")(mateweather_gettext ("Unknown"));
742 return weather_sky_string (info->sky);
743}
744
745const gchar *
746weather_info_get_conditions (WeatherInfo *info)
747{
748 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
749 if (!info->valid)
750 return "-";
751 return weather_conditions_string (info->cond);
752}
753
754static const gchar *
755temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
756{
757 static gchar buf[100];
758
759 switch (to_unit) {
760 case TEMP_UNIT_FAHRENHEIT:
761 if (!want_round) {
762 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
763 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
764 } else {
765 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
766 gdouble temp_r;
767
768 feclearexcept(range_problem);
769 temp_r = round (temp);
770 if (fetestexcept(range_problem))
771 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
772 else
773 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
774 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
775 }
776 break;
777 case TEMP_UNIT_CENTIGRADE:
778 if (!want_round) {
779 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
780 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)));
781 } else {
782 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
783 gdouble temp_r;
784
785 feclearexcept(range_problem);
786 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
787 if (fetestexcept(range_problem))
788 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
789 else
790 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
791 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
792 }
793 break;
794 case TEMP_UNIT_KELVIN:
795 if (!want_round) {
796 /* Translators: This is the temperature in kelvin */
797 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
798 } else {
799 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
800 gdouble temp_r;
801
802 feclearexcept(range_problem);
803 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
804 if (fetestexcept(range_problem))
805 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
806 else
807 /* Translators: This is the temperature in kelvin */
808 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
809 }
810 break;
811
812 case TEMP_UNIT_INVALID:
813 case TEMP_UNIT_DEFAULT:
814 default:
815 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
816 return _("Unknown")(mateweather_gettext ("Unknown"));
817 }
818
819 return buf;
820}
821
822const gchar *
823weather_info_get_temp (WeatherInfo *info)
824{
825 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
826
827 if (!info->valid)
828 return "-";
829 if (info->temp < -500.0)
830 return _("Unknown")(mateweather_gettext ("Unknown"));
831
832 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
833}
834
835const gchar *
836weather_info_get_temp_min (WeatherInfo *info)
837{
838 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
839
840 if (!info->valid || !info->tempMinMaxValid)
841 return "-";
842 if (info->temp_min < -500.0)
843 return _("Unknown")(mateweather_gettext ("Unknown"));
844
845 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
846}
847
848const gchar *
849weather_info_get_temp_max (WeatherInfo *info)
850{
851 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
852
853 if (!info->valid || !info->tempMinMaxValid)
854 return "-";
855 if (info->temp_max < -500.0)
856 return _("Unknown")(mateweather_gettext ("Unknown"));
857
858 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
859}
860
861const gchar *
862weather_info_get_dew (WeatherInfo *info)
863{
864 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
865
866 if (!info->valid)
867 return "-";
868 if (info->dew < -500.0)
869 return _("Unknown")(mateweather_gettext ("Unknown"));
870
871 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
872}
873
874const gchar *
875weather_info_get_humidity (WeatherInfo *info)
876{
877 static gchar buf[20];
878 gdouble humidity;
879
880 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
881
882 if (!info->valid)
883 return "-";
884
885 humidity = calc_humidity (info->temp, info->dew);
886 if (humidity < 0.0)
887 return _("Unknown")(mateweather_gettext ("Unknown"));
888
889 /* Translators: This is the humidity in percent */
890 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
891 return buf;
892}
893
894const gchar *
895weather_info_get_apparent (WeatherInfo *info)
896{
897 gdouble apparent;
898
899 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
900 if (!info->valid)
901 return "-";
902
903 apparent = calc_apparent (info);
904 if (apparent < -500.0)
905 return _("Unknown")(mateweather_gettext ("Unknown"));
906
907 return temperature_string (apparent, info->temperature_unit, FALSE(0));
908}
909
910static const gchar *
911windspeed_string (gfloat knots, SpeedUnit to_unit)
912{
913 static gchar buf[100];
914
915 switch (to_unit) {
916 case SPEED_UNIT_KNOTS:
917 /* Translators: This is the wind speed in knots */
918 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
919 break;
920 case SPEED_UNIT_MPH:
921 /* Translators: This is the wind speed in miles per hour */
922 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
923 break;
924 case SPEED_UNIT_KPH:
925 /* Translators: This is the wind speed in kilometers per hour */
926 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
927 break;
928 case SPEED_UNIT_MS:
929 /* Translators: This is the wind speed in meters per second */
930 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
931 break;
932 case SPEED_UNIT_BFT:
933 /* Translators: This is the wind speed as a Beaufort force factor
934 * (commonly used in nautical wind estimation).
935 */
936 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
937 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
938 break;
939 case SPEED_UNIT_INVALID:
940 case SPEED_UNIT_DEFAULT:
941 default:
942 g_warning ("Conversion to illegal speed unit: %d", to_unit);
943 return _("Unknown")(mateweather_gettext ("Unknown"));
944 }
945
946 return buf;
947}
948
949const gchar *
950weather_info_get_wind (WeatherInfo *info)
951{
952 static gchar buf[200];
953
954 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
955
956 if (!info->valid)
957 return "-";
958 if (info->windspeed < 0.0 || info->wind < 0)
959 return _("Unknown")(mateweather_gettext ("Unknown"));
960 if (info->windspeed == 0.00) {
961 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
962 buf[sizeof (buf)-1] = '\0';
963 } else {
964 /* Translators: This is 'wind direction' / 'wind speed' */
965 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
966 weather_wind_direction_string (info->wind),
967 windspeed_string (info->windspeed, info->speed_unit));
968 }
969 return buf;
970}
971
972const gchar *
973weather_info_get_pressure (WeatherInfo *info)
974{
975 static gchar buf[100];
976
977 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
978
979 if (!info->valid)
980 return "-";
981 if (info->pressure < 0.0)
982 return _("Unknown")(mateweather_gettext ("Unknown"));
983
984 switch (info->pressure_unit) {
985 case PRESSURE_UNIT_INCH_HG:
986 /* Translators: This is pressure in inches of mercury */
987 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
988 break;
989 case PRESSURE_UNIT_MM_HG:
990 /* Translators: This is pressure in millimeters of mercury */
991 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
992 break;
993 case PRESSURE_UNIT_KPA:
994 /* Translators: This is pressure in kiloPascals */
995 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
996 break;
997 case PRESSURE_UNIT_HPA:
998 /* Translators: This is pressure in hectoPascals */
999 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1000 break;
1001 case PRESSURE_UNIT_MB:
1002 /* Translators: This is pressure in millibars */
1003 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1004 break;
1005 case PRESSURE_UNIT_ATM:
1006 /* Translators: This is pressure in atmospheres */
1007 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1008 break;
1009
1010 case PRESSURE_UNIT_INVALID:
1011 case PRESSURE_UNIT_DEFAULT:
1012 default:
1013 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1014 return _("Unknown")(mateweather_gettext ("Unknown"));
1015 }
1016
1017 return buf;
1018}
1019
1020const gchar *
1021weather_info_get_visibility (WeatherInfo *info)
1022{
1023 static gchar buf[100];
1024
1025 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1026
1027 if (!info->valid)
1028 return "-";
1029 if (info->visibility < 0.0)
1030 return _("Unknown")(mateweather_gettext ("Unknown"));
1031
1032 switch (info->distance_unit) {
1033 case DISTANCE_UNIT_MILES:
1034 /* Translators: This is the visibility in miles */
1035 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1036 break;
1037 case DISTANCE_UNIT_KM:
1038 /* Translators: This is the visibility in kilometers */
1039 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1040 break;
1041 case DISTANCE_UNIT_METERS:
1042 /* Translators: This is the visibility in meters */
1043 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1044 break;
1045
1046 case DISTANCE_UNIT_INVALID:
1047 case DISTANCE_UNIT_DEFAULT:
1048 default:
1049 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1050 return _("Unknown")(mateweather_gettext ("Unknown"));
1051 }
1052
1053 return buf;
1054}
1055
1056const gchar *
1057weather_info_get_sunrise (WeatherInfo *info)
1058{
1059 static gchar buf[200];
1060 struct tm tm;
1061
1062 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)
;
1063
1064 if (!info->location->latlon_valid)
1065 return "-";
1066 if (!info->valid)
1067 return "-";
1068 if (!calc_sun (info))
1069 return "-";
1070
1071 localtime_r (&info->sunrise, &tm);
1072 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1073 return "-";
1074 return buf;
1075}
1076
1077const gchar *
1078weather_info_get_sunset (WeatherInfo *info)
1079{
1080 static gchar buf[200];
1081 struct tm tm;
1082
1083 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)
;
1084
1085 if (!info->location->latlon_valid)
1086 return "-";
1087 if (!info->valid)
1088 return "-";
1089 if (!calc_sun (info))
1090 return "-";
1091
1092 localtime_r (&info->sunset, &tm);
1093 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1094 return "-";
1095 return buf;
1096}
1097
1098const gchar *
1099weather_info_get_forecast (WeatherInfo *info)
1100{
1101 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1102 return info->forecast;
1103}
1104
1105/**
1106 * weather_info_get_forecast_list:
1107 * Returns list of WeatherInfo* objects for the forecast.
1108 * The list is owned by the 'info' object thus is alive as long
1109 * as the 'info'. This list is filled only when requested with
1110 * type FORECAST_LIST and if available for given location.
1111 * The 'update' property is the date/time when the forecast info
1112 * is used for.
1113 **/
1114GSList *
1115weather_info_get_forecast_list (WeatherInfo *info)
1116{
1117 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1118
1119 if (!info->valid)
1120 return NULL((void*)0);
1121
1122 return info->forecast_list;
1123}
1124
1125GdkPixbufAnimation *
1126weather_info_get_radar (WeatherInfo *info)
1127{
1128 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1129 return info->radar;
1130}
1131
1132const gchar *
1133weather_info_get_temp_summary (WeatherInfo *info)
1134{
1135 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1136
1137 if (!info->valid || info->temp < -500.0)
1138 return "--";
1139
1140 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1141
1142}
1143
1144gchar *
1145weather_info_get_weather_summary (WeatherInfo *info)
1146{
1147 const gchar *buf;
1148
1149 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1150
1151 if (!info->valid)
1152 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1153 buf = weather_info_get_conditions (info);
1154 if (!strcmp (buf, "-"))
1155 buf = weather_info_get_sky (info);
1156 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1157}
1158
1159const gchar *
1160weather_info_get_icon_name (WeatherInfo *info)
1161{
1162 WeatherConditions cond;
1163 WeatherSky sky;
1164 time_t current_time;
1165 gboolean daytime;
1166 gchar* icon;
1167 static gchar icon_buffer[32];
1168 WeatherMoonPhase moonPhase;
1169 WeatherMoonLatitude moonLat;
1170 gint phase;
1171
1172 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1173
1174 if (!info->valid)
1175 return NULL((void*)0);
1176
1177 cond = info->cond;
1178 sky = info->sky;
1179
1180 if (cond.significant) {
1181 if (cond.phenomenon != PHENOMENON_NONE &&
1182 cond.qualifier == QUALIFIER_THUNDERSTORM)
1183 return "weather-storm";
1184
1185 switch (cond.phenomenon) {
1186 case PHENOMENON_INVALID:
1187 case PHENOMENON_LAST:
1188 case PHENOMENON_NONE:
1189 break;
1190
1191 case PHENOMENON_DRIZZLE:
1192 case PHENOMENON_RAIN:
1193 case PHENOMENON_UNKNOWN_PRECIPITATION:
1194 case PHENOMENON_HAIL:
1195 case PHENOMENON_SMALL_HAIL:
1196 return "weather-showers";
1197
1198 case PHENOMENON_SNOW:
1199 case PHENOMENON_SNOW_GRAINS:
1200 case PHENOMENON_ICE_PELLETS:
1201 case PHENOMENON_ICE_CRYSTALS:
1202 return "weather-snow";
1203
1204 case PHENOMENON_TORNADO:
1205 case PHENOMENON_SQUALL:
1206 return "weather-storm";
1207
1208 case PHENOMENON_MIST:
1209 case PHENOMENON_FOG:
1210 case PHENOMENON_SMOKE:
1211 case PHENOMENON_VOLCANIC_ASH:
1212 case PHENOMENON_SAND:
1213 case PHENOMENON_HAZE:
1214 case PHENOMENON_SPRAY:
1215 case PHENOMENON_DUST:
1216 case PHENOMENON_SANDSTORM:
1217 case PHENOMENON_DUSTSTORM:
1218 case PHENOMENON_FUNNEL_CLOUD:
1219 case PHENOMENON_DUST_WHIRLS:
1220 return "weather-fog";
1221 }
1222 }
1223
1224 if (info->midnightSun ||
1225 (!info->sunriseValid && !info->sunsetValid))
1226 daytime = TRUE(!(0));
1227 else if (info->polarNight)
1228 daytime = FALSE(0);
1229 else {
1230 current_time = time (NULL((void*)0));
1231 daytime =
1232 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1233 ( !info->sunsetValid || (current_time < info->sunset) );
1234 }
1235
1236 switch (sky) {
1237 case SKY_INVALID:
1238 case SKY_LAST:
1239 case SKY_CLEAR:
1240 if (daytime)
1241 return "weather-clear";
1242 else {
1243 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1244 break;
1245 }
1246
1247 case SKY_BROKEN:
1248 case SKY_SCATTERED:
1249 case SKY_FEW:
1250 if (daytime)
1251 return "weather-few-clouds";
1252 else {
1253 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1254 break;
1255 }
1256
1257 case SKY_OVERCAST:
1258 return "weather-overcast";
1259
1260 default: /* unrecognized */
1261 return NULL((void*)0);
1262 }
1263
1264 /*
1265 * A phase-of-moon icon is to be returned.
1266 * Determine which one based on the moon's location
1267 */
1268 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1269 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1270 if (phase == MOON_PHASES36) {
1271 phase = 0;
1272 } else if (phase > 0 &&
1273 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1274 < moonLat)) {
1275 /*
1276 * Locations south of the moon's latitude will see the moon in the
1277 * northern sky. The moon waxes and wanes from left to right
1278 * so we reference an icon running in the opposite direction.
1279 */
1280 phase = MOON_PHASES36 - phase;
1281 }
1282
1283 /*
1284 * If the moon is not full then append the angle to the icon string.
1285 * Note that an icon by this name is not required to exist:
1286 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1287 * the full moon image.
1288 */
1289 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1290 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1291 "-%03d", phase * 360 / MOON_PHASES36);
1292 }
1293 }
1294 return icon_buffer;
1295}
1296
1297static gboolean
1298temperature_value (gdouble temp_f,
1299 TempUnit to_unit,
1300 gdouble *value,
1301 TempUnit def_unit)
1302{
1303 gboolean ok = TRUE(!(0));
1304
1305 *value = 0.0;
1306 if (temp_f < -500.0)
1307 return FALSE(0);
1308
1309 if (to_unit == TEMP_UNIT_DEFAULT)
1310 to_unit = def_unit;
1311
1312 switch (to_unit) {
1313 case TEMP_UNIT_FAHRENHEIT:
1314 *value = temp_f;
1315 break;
1316 case TEMP_UNIT_CENTIGRADE:
1317 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1318 break;
1319 case TEMP_UNIT_KELVIN:
1320 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1321 break;
1322 case TEMP_UNIT_INVALID:
1323 case TEMP_UNIT_DEFAULT:
1324 default:
1325 ok = FALSE(0);
1326 break;
1327 }
1328
1329 return ok;
1330}
1331
1332static gboolean
1333speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1334{
1335 gboolean ok = TRUE(!(0));
1336
1337 *value = -1.0;
1338
1339 if (knots < 0.0)
1340 return FALSE(0);
1341
1342 if (to_unit == SPEED_UNIT_DEFAULT)
1343 to_unit = def_unit;
1344
1345 switch (to_unit) {
1346 case SPEED_UNIT_KNOTS:
1347 *value = knots;
1348 break;
1349 case SPEED_UNIT_MPH:
1350 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1351 break;
1352 case SPEED_UNIT_KPH:
1353 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1354 break;
1355 case SPEED_UNIT_MS:
1356 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1357 break;
1358 case SPEED_UNIT_BFT:
1359 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1360 break;
1361 case SPEED_UNIT_INVALID:
1362 case SPEED_UNIT_DEFAULT:
1363 default:
1364 ok = FALSE(0);
1365 break;
1366 }
1367
1368 return ok;
1369}
1370
1371static gboolean
1372pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1373{
1374 gboolean ok = TRUE(!(0));
1375
1376 *value = -1.0;
1377
1378 if (inHg < 0.0)
1379 return FALSE(0);
1380
1381 if (to_unit == PRESSURE_UNIT_DEFAULT)
1382 to_unit = def_unit;
1383
1384 switch (to_unit) {
1385 case PRESSURE_UNIT_INCH_HG:
1386 *value = inHg;
1387 break;
1388 case PRESSURE_UNIT_MM_HG:
1389 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1390 break;
1391 case PRESSURE_UNIT_KPA:
1392 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1393 break;
1394 case PRESSURE_UNIT_HPA:
1395 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1396 break;
1397 case PRESSURE_UNIT_MB:
1398 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1399 break;
1400 case PRESSURE_UNIT_ATM:
1401 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1402 break;
1403 case PRESSURE_UNIT_INVALID:
1404 case PRESSURE_UNIT_DEFAULT:
1405 default:
1406 ok = FALSE(0);
1407 break;
1408 }
1409
1410 return ok;
1411}
1412
1413static gboolean
1414distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1415{
1416 gboolean ok = TRUE(!(0));
1417
1418 *value = -1.0;
1419
1420 if (miles < 0.0)
1421 return FALSE(0);
1422
1423 if (to_unit == DISTANCE_UNIT_DEFAULT)
1424 to_unit = def_unit;
1425
1426 switch (to_unit) {
1427 case DISTANCE_UNIT_MILES:
1428 *value = miles;
1429 break;
1430 case DISTANCE_UNIT_KM:
1431 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1432 break;
1433 case DISTANCE_UNIT_METERS:
1434 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1435 break;
1436 case DISTANCE_UNIT_INVALID:
1437 case DISTANCE_UNIT_DEFAULT:
1438 default:
1439 ok = FALSE(0);
1440 break;
1441 }
1442
1443 return ok;
1444}
1445
1446gboolean
1447weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1448{
1449 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1450 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)
;
1451
1452 if (!info->valid)
1453 return FALSE(0);
1454
1455 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1456 return FALSE(0);
1457
1458 *sky = info->sky;
1459
1460 return TRUE(!(0));
1461}
1462
1463gboolean
1464weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1465{
1466 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1467 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)
;
1468 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)
;
1469
1470 if (!info->valid)
1471 return FALSE(0);
1472
1473 if (!info->cond.significant)
1474 return FALSE(0);
1475
1476 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1477 info->cond.phenomenon < PHENOMENON_LAST &&
1478 info->cond.qualifier > QUALIFIER_INVALID &&
1479 info->cond.qualifier < QUALIFIER_LAST))
1480 return FALSE(0);
1481
1482 *phenomenon = info->cond.phenomenon;
1483 *qualifier = info->cond.qualifier;
1484
1485 return TRUE(!(0));
1486}
1487
1488gboolean
1489weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1490{
1491 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1492 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)
;
1493
1494 if (!info->valid)
1495 return FALSE(0);
1496
1497 return temperature_value (info->temp, unit, value, info->temperature_unit);
1498}
1499
1500gboolean
1501weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1502{
1503 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1504 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)
;
1505
1506 if (!info->valid || !info->tempMinMaxValid)
1507 return FALSE(0);
1508
1509 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1510}
1511
1512gboolean
1513weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1514{
1515 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1516 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)
;
1517
1518 if (!info->valid || !info->tempMinMaxValid)
1519 return FALSE(0);
1520
1521 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1522}
1523
1524gboolean
1525weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1526{
1527 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1528 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)
;
1529
1530 if (!info->valid)
1531 return FALSE(0);
1532
1533 return temperature_value (info->dew, unit, value, info->temperature_unit);
1534}
1535
1536gboolean
1537weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1538{
1539 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1540 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)
;
1541
1542 if (!info->valid)
1543 return FALSE(0);
1544
1545 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1546}
1547
1548gboolean
1549weather_info_get_value_update (WeatherInfo *info, time_t *value)
1550{
1551 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1552 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)
;
1553
1554 if (!info->valid)
1555 return FALSE(0);
1556
1557 *value = info->update;
1558
1559 return TRUE(!(0));
1560}
1561
1562gboolean
1563weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1564{
1565 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1566 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)
;
1567
1568 if (!info->valid || !info->sunriseValid)
1569 return FALSE(0);
1570
1571 *value = info->sunrise;
1572
1573 return TRUE(!(0));
1574}
1575
1576gboolean
1577weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1578{
1579 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1580 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)
;
1581
1582 if (!info->valid || !info->sunsetValid)
1583 return FALSE(0);
1584
1585 *value = info->sunset;
1586
1587 return TRUE(!(0));
1588}
1589
1590gboolean
1591weather_info_get_value_moonphase (WeatherInfo *info,
1592 WeatherMoonPhase *value,
1593 WeatherMoonLatitude *lat)
1594{
1595 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1596 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)
;
1597
1598 if (!info->valid || !info->moonValid)
1599 return FALSE(0);
1600
1601 *value = info->moonphase;
1602 *lat = info->moonlatitude;
1603
1604 return TRUE(!(0));
1605}
1606
1607gboolean
1608weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1609{
1610 gboolean res = FALSE(0);
1611
1612 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1613 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)
;
1614 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)
;
1615
1616 if (!info->valid)
1617 return FALSE(0);
1618
1619 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1620 return FALSE(0);
1621
1622 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1623 *direction = info->wind;
1624
1625 return res;
1626}
1627
1628gboolean
1629weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1630{
1631 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1632 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)
;
1633
1634 if (!info->valid)
1635 return FALSE(0);
1636
1637 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1638}
1639
1640gboolean
1641weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1642{
1643 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1644 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)
;
1645
1646 if (!info->valid)
1647 return FALSE(0);
1648
1649 return distance_value (info->visibility, unit, value, info->distance_unit);
1650}
1651
1652/**
1653 * weather_info_get_upcoming_moonphases:
1654 * @info: WeatherInfo containing the time_t of interest
1655 * @phases: An array of four time_t values that will hold the returned values.
1656 * The values are estimates of the time of the next new, quarter, full and
1657 * three-quarter moons.
1658 *
1659 * Returns: gboolean indicating success or failure
1660 */
1661gboolean
1662weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1663{
1664 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1665 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)
;
1666
1667 return calc_moon_phases(info, phases);
1668}
1669
1670static void
1671_weather_internal_check (void)
1672{
1673 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", 1673, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1674 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"
, 1674, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1676 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", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1677}
diff --git a/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-565489.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-565489.html new file mode 100644 index 0000000..c16a586 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-565489.html @@ -0,0 +1,2029 @@ + + + +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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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"
); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval
; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic
= (&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_new ();
557 }
558
559 metar_start_open (info);
560 iwin_start_open (info);
561
562 if (prefs->radar) {
563 wx_start_open (info);
564 }
565
566 return info;
567}
568
569void
570weather_info_abort (WeatherInfo *info)
571{
572 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)
;
573
574 if (info->session) {
575 soup_session_abort (info->session);
576 info->requests_pending = 0;
577 }
578}
579
580WeatherInfo *
581weather_info_clone (const WeatherInfo *info)
582{
583 WeatherInfo *clone;
584
585 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
586
587 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; }))
;
588
589
590 /* move everything */
591 memmove (clone, info, sizeof (WeatherInfo));
592
593
594 /* special moves */
595 clone->location = weather_location_clone (info->location);
596 /* This handles null correctly */
597 clone->forecast = g_strdup (info->forecast);
598 clone->radar_url = g_strdup (info->radar_url);
599
600 if (info->forecast_list) {
601 GSList *p;
602
603 clone->forecast_list = NULL((void*)0);
604 for (p = info->forecast_list; p; p = p->next) {
605 clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
606 }
607
608 clone->forecast_list = g_slist_reverse (clone->forecast_list);
609 }
610
611 clone->radar = info->radar;
612 if (clone->radar != NULL((void*)0))
613 g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar
))
;
614
615 return clone;
616}
617
618void
619weather_info_free (WeatherInfo *info)
620{
621 if (!info)
622 return;
623
624 weather_info_abort (info);
625 if (info->session)
626 g_object_unref (info->session);
627
628 weather_location_free (info->location);
629 info->location = NULL((void*)0);
630
631 g_free (info->forecast);
632 info->forecast = NULL((void*)0);
633
634 free_forecast_list (info);
635
636 if (info->radar != NULL((void*)0)) {
637 g_object_unref (info->radar);
638 info->radar = NULL((void*)0);
639 }
640
641 g_free (info);
642}
643
644gboolean
645weather_info_is_valid (WeatherInfo *info)
646{
647 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
648 return info->valid;
649}
650
651gboolean
652weather_info_network_error (WeatherInfo *info)
653{
654 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
655 return info->network_error;
656}
657
658void
659weather_info_to_metric (WeatherInfo *info)
660{
661 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)
;
662
663 info->temperature_unit = TEMP_UNIT_CENTIGRADE;
664 info->speed_unit = SPEED_UNIT_MS;
665 info->pressure_unit = PRESSURE_UNIT_HPA;
666 info->distance_unit = DISTANCE_UNIT_METERS;
667}
668
669void
670weather_info_to_imperial (WeatherInfo *info)
671{
672 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)
;
673
674 info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
675 info->speed_unit = SPEED_UNIT_MPH;
676 info->pressure_unit = PRESSURE_UNIT_INCH_HG;
677 info->distance_unit = DISTANCE_UNIT_MILES;
678}
679
680const WeatherLocation *
681weather_info_get_location (WeatherInfo *info)
682{
683 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
684 return info->location;
685}
686
687const gchar *
688weather_info_get_location_name (WeatherInfo *info)
689{
690 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
691 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)
;
692 return info->location->name;
693}
694
695const gchar *
696weather_info_get_update (WeatherInfo *info)
697{
698 static gchar buf[200];
699 char *utf8, *timeformat;
700
701 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
702
703 if (!info->valid)
704 return "-";
705
706 if (info->update != 0) {
707 struct tm tm;
708 localtime_r (&info->update, &tm);
709 /* Translators: this is a format string for strftime
710 * see `man 3 strftime` for more details
711 */
712 timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1,
713 NULL((void*)0), NULL((void*)0), NULL((void*)0));
714 if (!timeformat) {
715 strcpy (buf, "???");
716 }
717 else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) {
718 strcpy (buf, "???");
719 }
720 g_free (timeformat);
721
722 /* Convert to UTF-8 */
723 utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
724 strcpy (buf, utf8);
725 g_free (utf8);
726 } else {
727 strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf));
728 buf[sizeof (buf)-1] = '\0';
729 }
730
731 return buf;
732}
733
734const gchar *
735weather_info_get_sky (WeatherInfo *info)
736{
737 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
738 if (!info->valid)
739 return "-";
740 if (info->sky < 0)
741 return _("Unknown")(mateweather_gettext ("Unknown"));
742 return weather_sky_string (info->sky);
743}
744
745const gchar *
746weather_info_get_conditions (WeatherInfo *info)
747{
748 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
749 if (!info->valid)
750 return "-";
751 return weather_conditions_string (info->cond);
752}
753
754static const gchar *
755temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round)
756{
757 static gchar buf[100];
758
759 switch (to_unit) {
760 case TEMP_UNIT_FAHRENHEIT:
761 if (!want_round) {
762 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
763 g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp);
764 } else {
765 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
766 gdouble temp_r;
767
768 feclearexcept(range_problem);
769 temp_r = round (temp);
770 if (fetestexcept(range_problem))
771 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
772 else
773 /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */
774 g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r);
775 }
776 break;
777 case TEMP_UNIT_CENTIGRADE:
778 if (!want_round) {
779 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
780 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)));
781 } else {
782 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
783 gdouble temp_r;
784
785 feclearexcept(range_problem);
786 temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)));
787 if (fetestexcept(range_problem))
788 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
789 else
790 /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */
791 g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r);
792 }
793 break;
794 case TEMP_UNIT_KELVIN:
795 if (!want_round) {
796 /* Translators: This is the temperature in kelvin */
797 g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
798 } else {
799 const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10;
800 gdouble temp_r;
801
802 feclearexcept(range_problem);
803 temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0)));
804 if (fetestexcept(range_problem))
805 g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a")));
806 else
807 /* Translators: This is the temperature in kelvin */
808 g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r);
809 }
810 break;
811
812 case TEMP_UNIT_INVALID:
813 case TEMP_UNIT_DEFAULT:
814 default:
815 g_warning ("Conversion to illegal temperature unit: %d", to_unit);
816 return _("Unknown")(mateweather_gettext ("Unknown"));
817 }
818
819 return buf;
820}
821
822const gchar *
823weather_info_get_temp (WeatherInfo *info)
824{
825 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
826
827 if (!info->valid)
828 return "-";
829 if (info->temp < -500.0)
830 return _("Unknown")(mateweather_gettext ("Unknown"));
831
832 return temperature_string (info->temp, info->temperature_unit, FALSE(0));
833}
834
835const gchar *
836weather_info_get_temp_min (WeatherInfo *info)
837{
838 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
839
840 if (!info->valid || !info->tempMinMaxValid)
841 return "-";
842 if (info->temp_min < -500.0)
843 return _("Unknown")(mateweather_gettext ("Unknown"));
844
845 return temperature_string (info->temp_min, info->temperature_unit, FALSE(0));
846}
847
848const gchar *
849weather_info_get_temp_max (WeatherInfo *info)
850{
851 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
852
853 if (!info->valid || !info->tempMinMaxValid)
854 return "-";
855 if (info->temp_max < -500.0)
856 return _("Unknown")(mateweather_gettext ("Unknown"));
857
858 return temperature_string (info->temp_max, info->temperature_unit, FALSE(0));
859}
860
861const gchar *
862weather_info_get_dew (WeatherInfo *info)
863{
864 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
865
866 if (!info->valid)
867 return "-";
868 if (info->dew < -500.0)
869 return _("Unknown")(mateweather_gettext ("Unknown"));
870
871 return temperature_string (info->dew, info->temperature_unit, FALSE(0));
872}
873
874const gchar *
875weather_info_get_humidity (WeatherInfo *info)
876{
877 static gchar buf[20];
878 gdouble humidity;
879
880 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
881
882 if (!info->valid)
883 return "-";
884
885 humidity = calc_humidity (info->temp, info->dew);
886 if (humidity < 0.0)
887 return _("Unknown")(mateweather_gettext ("Unknown"));
888
889 /* Translators: This is the humidity in percent */
890 g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity);
891 return buf;
892}
893
894const gchar *
895weather_info_get_apparent (WeatherInfo *info)
896{
897 gdouble apparent;
898
899 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
900 if (!info->valid)
901 return "-";
902
903 apparent = calc_apparent (info);
904 if (apparent < -500.0)
905 return _("Unknown")(mateweather_gettext ("Unknown"));
906
907 return temperature_string (apparent, info->temperature_unit, FALSE(0));
908}
909
910static const gchar *
911windspeed_string (gfloat knots, SpeedUnit to_unit)
912{
913 static gchar buf[100];
914
915 switch (to_unit) {
916 case SPEED_UNIT_KNOTS:
917 /* Translators: This is the wind speed in knots */
918 g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots);
919 break;
920 case SPEED_UNIT_MPH:
921 /* Translators: This is the wind speed in miles per hour */
922 g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779));
923 break;
924 case SPEED_UNIT_KPH:
925 /* Translators: This is the wind speed in kilometers per hour */
926 g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965));
927 break;
928 case SPEED_UNIT_MS:
929 /* Translators: This is the wind speed in meters per second */
930 g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444));
931 break;
932 case SPEED_UNIT_BFT:
933 /* Translators: This is the wind speed as a Beaufort force factor
934 * (commonly used in nautical wind estimation).
935 */
936 g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")),
937 WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)));
938 break;
939 case SPEED_UNIT_INVALID:
940 case SPEED_UNIT_DEFAULT:
941 default:
942 g_warning ("Conversion to illegal speed unit: %d", to_unit);
943 return _("Unknown")(mateweather_gettext ("Unknown"));
944 }
945
946 return buf;
947}
948
949const gchar *
950weather_info_get_wind (WeatherInfo *info)
951{
952 static gchar buf[200];
953
954 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
955
956 if (!info->valid)
957 return "-";
958 if (info->windspeed < 0.0 || info->wind < 0)
959 return _("Unknown")(mateweather_gettext ("Unknown"));
960 if (info->windspeed == 0.00) {
961 strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf));
962 buf[sizeof (buf)-1] = '\0';
963 } else {
964 /* Translators: This is 'wind direction' / 'wind speed' */
965 g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")),
966 weather_wind_direction_string (info->wind),
967 windspeed_string (info->windspeed, info->speed_unit));
968 }
969 return buf;
970}
971
972const gchar *
973weather_info_get_pressure (WeatherInfo *info)
974{
975 static gchar buf[100];
976
977 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
978
979 if (!info->valid)
980 return "-";
981 if (info->pressure < 0.0)
982 return _("Unknown")(mateweather_gettext ("Unknown"));
983
984 switch (info->pressure_unit) {
985 case PRESSURE_UNIT_INCH_HG:
986 /* Translators: This is pressure in inches of mercury */
987 g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure);
988 break;
989 case PRESSURE_UNIT_MM_HG:
990 /* Translators: This is pressure in millimeters of mercury */
991 g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005));
992 break;
993 case PRESSURE_UNIT_KPA:
994 /* Translators: This is pressure in kiloPascals */
995 g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386));
996 break;
997 case PRESSURE_UNIT_HPA:
998 /* Translators: This is pressure in hectoPascals */
999 g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86));
1000 break;
1001 case PRESSURE_UNIT_MB:
1002 /* Translators: This is pressure in millibars */
1003 g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86)));
1004 break;
1005 case PRESSURE_UNIT_ATM:
1006 /* Translators: This is pressure in atmospheres */
1007 g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052));
1008 break;
1009
1010 case PRESSURE_UNIT_INVALID:
1011 case PRESSURE_UNIT_DEFAULT:
1012 default:
1013 g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit);
1014 return _("Unknown")(mateweather_gettext ("Unknown"));
1015 }
1016
1017 return buf;
1018}
1019
1020const gchar *
1021weather_info_get_visibility (WeatherInfo *info)
1022{
1023 static gchar buf[100];
1024
1025 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1026
1027 if (!info->valid)
1028 return "-";
1029 if (info->visibility < 0.0)
1030 return _("Unknown")(mateweather_gettext ("Unknown"));
1031
1032 switch (info->distance_unit) {
1033 case DISTANCE_UNIT_MILES:
1034 /* Translators: This is the visibility in miles */
1035 g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility);
1036 break;
1037 case DISTANCE_UNIT_KM:
1038 /* Translators: This is the visibility in kilometers */
1039 g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344));
1040 break;
1041 case DISTANCE_UNIT_METERS:
1042 /* Translators: This is the visibility in meters */
1043 g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000));
1044 break;
1045
1046 case DISTANCE_UNIT_INVALID:
1047 case DISTANCE_UNIT_DEFAULT:
1048 default:
1049 g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit);
1050 return _("Unknown")(mateweather_gettext ("Unknown"));
1051 }
1052
1053 return buf;
1054}
1055
1056const gchar *
1057weather_info_get_sunrise (WeatherInfo *info)
1058{
1059 static gchar buf[200];
1060 struct tm tm;
1061
1062 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)
;
1063
1064 if (!info->location->latlon_valid)
1065 return "-";
1066 if (!info->valid)
1067 return "-";
1068 if (!calc_sun (info))
1069 return "-";
1070
1071 localtime_r (&info->sunrise, &tm);
1072 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1073 return "-";
1074 return buf;
1075}
1076
1077const gchar *
1078weather_info_get_sunset (WeatherInfo *info)
1079{
1080 static gchar buf[200];
1081 struct tm tm;
1082
1083 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)
;
1084
1085 if (!info->location->latlon_valid)
1086 return "-";
1087 if (!info->valid)
1088 return "-";
1089 if (!calc_sun (info))
1090 return "-";
1091
1092 localtime_r (&info->sunset, &tm);
1093 if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0)
1094 return "-";
1095 return buf;
1096}
1097
1098const gchar *
1099weather_info_get_forecast (WeatherInfo *info)
1100{
1101 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1102 return info->forecast;
1103}
1104
1105/**
1106 * weather_info_get_forecast_list:
1107 * Returns list of WeatherInfo* objects for the forecast.
1108 * The list is owned by the 'info' object thus is alive as long
1109 * as the 'info'. This list is filled only when requested with
1110 * type FORECAST_LIST and if available for given location.
1111 * The 'update' property is the date/time when the forecast info
1112 * is used for.
1113 **/
1114GSList *
1115weather_info_get_forecast_list (WeatherInfo *info)
1116{
1117 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1118
1119 if (!info->valid)
1120 return NULL((void*)0);
1121
1122 return info->forecast_list;
1123}
1124
1125GdkPixbufAnimation *
1126weather_info_get_radar (WeatherInfo *info)
1127{
1128 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1129 return info->radar;
1130}
1131
1132const gchar *
1133weather_info_get_temp_summary (WeatherInfo *info)
1134{
1135 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1136
1137 if (!info->valid || info->temp < -500.0)
1138 return "--";
1139
1140 return temperature_string (info->temp, info->temperature_unit, TRUE(!(0)));
1141
1142}
1143
1144gchar *
1145weather_info_get_weather_summary (WeatherInfo *info)
1146{
1147 const gchar *buf;
1148
1149 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1150
1151 if (!info->valid)
1152 return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed")));
1153 buf = weather_info_get_conditions (info);
1154 if (!strcmp (buf, "-"))
1155 buf = weather_info_get_sky (info);
1156 return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1157}
1158
1159const gchar *
1160weather_info_get_icon_name (WeatherInfo *info)
1161{
1162 WeatherConditions cond;
1163 WeatherSky sky;
1164 time_t current_time;
1165 gboolean daytime;
1166 gchar* icon;
1167 static gchar icon_buffer[32];
1168 WeatherMoonPhase moonPhase;
1169 WeatherMoonLatitude moonLat;
1170 gint phase;
1171
1172 g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return (((void*)0)); } } while (0)
;
1173
1174 if (!info->valid)
1175 return NULL((void*)0);
1176
1177 cond = info->cond;
1178 sky = info->sky;
1179
1180 if (cond.significant) {
1181 if (cond.phenomenon != PHENOMENON_NONE &&
1182 cond.qualifier == QUALIFIER_THUNDERSTORM)
1183 return "weather-storm";
1184
1185 switch (cond.phenomenon) {
1186 case PHENOMENON_INVALID:
1187 case PHENOMENON_LAST:
1188 case PHENOMENON_NONE:
1189 break;
1190
1191 case PHENOMENON_DRIZZLE:
1192 case PHENOMENON_RAIN:
1193 case PHENOMENON_UNKNOWN_PRECIPITATION:
1194 case PHENOMENON_HAIL:
1195 case PHENOMENON_SMALL_HAIL:
1196 return "weather-showers";
1197
1198 case PHENOMENON_SNOW:
1199 case PHENOMENON_SNOW_GRAINS:
1200 case PHENOMENON_ICE_PELLETS:
1201 case PHENOMENON_ICE_CRYSTALS:
1202 return "weather-snow";
1203
1204 case PHENOMENON_TORNADO:
1205 case PHENOMENON_SQUALL:
1206 return "weather-storm";
1207
1208 case PHENOMENON_MIST:
1209 case PHENOMENON_FOG:
1210 case PHENOMENON_SMOKE:
1211 case PHENOMENON_VOLCANIC_ASH:
1212 case PHENOMENON_SAND:
1213 case PHENOMENON_HAZE:
1214 case PHENOMENON_SPRAY:
1215 case PHENOMENON_DUST:
1216 case PHENOMENON_SANDSTORM:
1217 case PHENOMENON_DUSTSTORM:
1218 case PHENOMENON_FUNNEL_CLOUD:
1219 case PHENOMENON_DUST_WHIRLS:
1220 return "weather-fog";
1221 }
1222 }
1223
1224 if (info->midnightSun ||
1225 (!info->sunriseValid && !info->sunsetValid))
1226 daytime = TRUE(!(0));
1227 else if (info->polarNight)
1228 daytime = FALSE(0);
1229 else {
1230 current_time = time (NULL((void*)0));
1231 daytime =
1232 ( !info->sunriseValid || (current_time >= info->sunrise) ) &&
1233 ( !info->sunsetValid || (current_time < info->sunset) );
1234 }
1235
1236 switch (sky) {
1237 case SKY_INVALID:
1238 case SKY_LAST:
1239 case SKY_CLEAR:
1240 if (daytime)
1241 return "weather-clear";
1242 else {
1243 icon = g_stpcpy(icon_buffer, "weather-clear-night");
1244 break;
1245 }
1246
1247 case SKY_BROKEN:
1248 case SKY_SCATTERED:
1249 case SKY_FEW:
1250 if (daytime)
1251 return "weather-few-clouds";
1252 else {
1253 icon = g_stpcpy(icon_buffer, "weather-few-clouds-night");
1254 break;
1255 }
1256
1257 case SKY_OVERCAST:
1258 return "weather-overcast";
1259
1260 default: /* unrecognized */
1261 return NULL((void*)0);
1262 }
1263
1264 /*
1265 * A phase-of-moon icon is to be returned.
1266 * Determine which one based on the moon's location
1267 */
1268 if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) {
1269 phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5);
1270 if (phase == MOON_PHASES36) {
1271 phase = 0;
1272 } else if (phase > 0 &&
1273 (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846
)
1274 < moonLat)) {
1275 /*
1276 * Locations south of the moon's latitude will see the moon in the
1277 * northern sky. The moon waxes and wanes from left to right
1278 * so we reference an icon running in the opposite direction.
1279 */
1280 phase = MOON_PHASES36 - phase;
1281 }
1282
1283 /*
1284 * If the moon is not full then append the angle to the icon string.
1285 * Note that an icon by this name is not required to exist:
1286 * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to
1287 * the full moon image.
1288 */
1289 if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) {
1290 g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer),
1291 "-%03d", phase * 360 / MOON_PHASES36);
1292 }
1293 }
1294 return icon_buffer;
1295}
1296
1297static gboolean
1298temperature_value (gdouble temp_f,
1299 TempUnit to_unit,
1300 gdouble *value,
1301 TempUnit def_unit)
1302{
1303 gboolean ok = TRUE(!(0));
1304
1305 *value = 0.0;
1306 if (temp_f < -500.0)
1307 return FALSE(0);
1308
1309 if (to_unit == TEMP_UNIT_DEFAULT)
1310 to_unit = def_unit;
1311
1312 switch (to_unit) {
1313 case TEMP_UNIT_FAHRENHEIT:
1314 *value = temp_f;
1315 break;
1316 case TEMP_UNIT_CENTIGRADE:
1317 *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0));
1318 break;
1319 case TEMP_UNIT_KELVIN:
1320 *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0));
1321 break;
1322 case TEMP_UNIT_INVALID:
1323 case TEMP_UNIT_DEFAULT:
1324 default:
1325 ok = FALSE(0);
1326 break;
1327 }
1328
1329 return ok;
1330}
1331
1332static gboolean
1333speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
1334{
1335 gboolean ok = TRUE(!(0));
1336
1337 *value = -1.0;
1338
1339 if (knots < 0.0)
1340 return FALSE(0);
1341
1342 if (to_unit == SPEED_UNIT_DEFAULT)
1343 to_unit = def_unit;
1344
1345 switch (to_unit) {
1346 case SPEED_UNIT_KNOTS:
1347 *value = knots;
1348 break;
1349 case SPEED_UNIT_MPH:
1350 *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779);
1351 break;
1352 case SPEED_UNIT_KPH:
1353 *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965);
1354 break;
1355 case SPEED_UNIT_MS:
1356 *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444);
1357 break;
1358 case SPEED_UNIT_BFT:
1359 *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666));
1360 break;
1361 case SPEED_UNIT_INVALID:
1362 case SPEED_UNIT_DEFAULT:
1363 default:
1364 ok = FALSE(0);
1365 break;
1366 }
1367
1368 return ok;
1369}
1370
1371static gboolean
1372pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
1373{
1374 gboolean ok = TRUE(!(0));
1375
1376 *value = -1.0;
1377
1378 if (inHg < 0.0)
1379 return FALSE(0);
1380
1381 if (to_unit == PRESSURE_UNIT_DEFAULT)
1382 to_unit = def_unit;
1383
1384 switch (to_unit) {
1385 case PRESSURE_UNIT_INCH_HG:
1386 *value = inHg;
1387 break;
1388 case PRESSURE_UNIT_MM_HG:
1389 *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005);
1390 break;
1391 case PRESSURE_UNIT_KPA:
1392 *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386);
1393 break;
1394 case PRESSURE_UNIT_HPA:
1395 *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86);
1396 break;
1397 case PRESSURE_UNIT_MB:
1398 *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86));
1399 break;
1400 case PRESSURE_UNIT_ATM:
1401 *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052);
1402 break;
1403 case PRESSURE_UNIT_INVALID:
1404 case PRESSURE_UNIT_DEFAULT:
1405 default:
1406 ok = FALSE(0);
1407 break;
1408 }
1409
1410 return ok;
1411}
1412
1413static gboolean
1414distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
1415{
1416 gboolean ok = TRUE(!(0));
1417
1418 *value = -1.0;
1419
1420 if (miles < 0.0)
1421 return FALSE(0);
1422
1423 if (to_unit == DISTANCE_UNIT_DEFAULT)
1424 to_unit = def_unit;
1425
1426 switch (to_unit) {
1427 case DISTANCE_UNIT_MILES:
1428 *value = miles;
1429 break;
1430 case DISTANCE_UNIT_KM:
1431 *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344);
1432 break;
1433 case DISTANCE_UNIT_METERS:
1434 *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000);
1435 break;
1436 case DISTANCE_UNIT_INVALID:
1437 case DISTANCE_UNIT_DEFAULT:
1438 default:
1439 ok = FALSE(0);
1440 break;
1441 }
1442
1443 return ok;
1444}
1445
1446gboolean
1447weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
1448{
1449 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1450 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)
;
1451
1452 if (!info->valid)
1453 return FALSE(0);
1454
1455 if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST)
1456 return FALSE(0);
1457
1458 *sky = info->sky;
1459
1460 return TRUE(!(0));
1461}
1462
1463gboolean
1464weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
1465{
1466 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1467 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)
;
1468 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)
;
1469
1470 if (!info->valid)
1471 return FALSE(0);
1472
1473 if (!info->cond.significant)
1474 return FALSE(0);
1475
1476 if (!(info->cond.phenomenon > PHENOMENON_INVALID &&
1477 info->cond.phenomenon < PHENOMENON_LAST &&
1478 info->cond.qualifier > QUALIFIER_INVALID &&
1479 info->cond.qualifier < QUALIFIER_LAST))
1480 return FALSE(0);
1481
1482 *phenomenon = info->cond.phenomenon;
1483 *qualifier = info->cond.qualifier;
1484
1485 return TRUE(!(0));
1486}
1487
1488gboolean
1489weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
1490{
1491 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1492 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)
;
1493
1494 if (!info->valid)
1495 return FALSE(0);
1496
1497 return temperature_value (info->temp, unit, value, info->temperature_unit);
1498}
1499
1500gboolean
1501weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
1502{
1503 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1504 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)
;
1505
1506 if (!info->valid || !info->tempMinMaxValid)
1507 return FALSE(0);
1508
1509 return temperature_value (info->temp_min, unit, value, info->temperature_unit);
1510}
1511
1512gboolean
1513weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
1514{
1515 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1516 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)
;
1517
1518 if (!info->valid || !info->tempMinMaxValid)
1519 return FALSE(0);
1520
1521 return temperature_value (info->temp_max, unit, value, info->temperature_unit);
1522}
1523
1524gboolean
1525weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
1526{
1527 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1528 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)
;
1529
1530 if (!info->valid)
1531 return FALSE(0);
1532
1533 return temperature_value (info->dew, unit, value, info->temperature_unit);
1534}
1535
1536gboolean
1537weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
1538{
1539 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1540 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)
;
1541
1542 if (!info->valid)
1543 return FALSE(0);
1544
1545 return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
1546}
1547
1548gboolean
1549weather_info_get_value_update (WeatherInfo *info, time_t *value)
1550{
1551 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1552 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)
;
1553
1554 if (!info->valid)
1555 return FALSE(0);
1556
1557 *value = info->update;
1558
1559 return TRUE(!(0));
1560}
1561
1562gboolean
1563weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
1564{
1565 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1566 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)
;
1567
1568 if (!info->valid || !info->sunriseValid)
1569 return FALSE(0);
1570
1571 *value = info->sunrise;
1572
1573 return TRUE(!(0));
1574}
1575
1576gboolean
1577weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
1578{
1579 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1580 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)
;
1581
1582 if (!info->valid || !info->sunsetValid)
1583 return FALSE(0);
1584
1585 *value = info->sunset;
1586
1587 return TRUE(!(0));
1588}
1589
1590gboolean
1591weather_info_get_value_moonphase (WeatherInfo *info,
1592 WeatherMoonPhase *value,
1593 WeatherMoonLatitude *lat)
1594{
1595 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1596 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)
;
1597
1598 if (!info->valid || !info->moonValid)
1599 return FALSE(0);
1600
1601 *value = info->moonphase;
1602 *lat = info->moonlatitude;
1603
1604 return TRUE(!(0));
1605}
1606
1607gboolean
1608weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
1609{
1610 gboolean res = FALSE(0);
1611
1612 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1613 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)
;
1614 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)
;
1615
1616 if (!info->valid)
1617 return FALSE(0);
1618
1619 if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST)
1620 return FALSE(0);
1621
1622 res = speed_value (info->windspeed, unit, speed, info->speed_unit);
1623 *direction = info->wind;
1624
1625 return res;
1626}
1627
1628gboolean
1629weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
1630{
1631 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1632 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)
;
1633
1634 if (!info->valid)
1635 return FALSE(0);
1636
1637 return pressure_value (info->pressure, unit, value, info->pressure_unit);
1638}
1639
1640gboolean
1641weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
1642{
1643 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1644 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)
;
1645
1646 if (!info->valid)
1647 return FALSE(0);
1648
1649 return distance_value (info->visibility, unit, value, info->distance_unit);
1650}
1651
1652/**
1653 * weather_info_get_upcoming_moonphases:
1654 * @info: WeatherInfo containing the time_t of interest
1655 * @phases: An array of four time_t values that will hold the returned values.
1656 * The values are estimates of the time of the next new, quarter, full and
1657 * three-quarter moons.
1658 *
1659 * Returns: gboolean indicating success or failure
1660 */
1661gboolean
1662weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases)
1663{
1664 g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_
; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning
("MateWeather", ((const char*) (__func__)), "info != NULL");
return ((0)); } } while (0)
;
1665 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)
;
1666
1667 return calc_moon_phases(info, phases);
1668}
1669
1670static void
1671_weather_internal_check (void)
1672{
1673 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", 1673, ((const char*) (__func__)
), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while
(0)
;
1674 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"
, 1674, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST"
); } while (0)
;
1675 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", 1675, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while
(0)
;
1676 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", 1676, ((const char*) (__func__)
), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while
(0)
;
1677}
diff --git a/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-a36726.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-a36726.html new file mode 100644 index 0000000..48b0073 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-a36726.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ae87bd.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ae87bd.html new file mode 100644 index 0000000..60e8f6b --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ae87bd.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-c44f01.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-c44f01.html new file mode 100644 index 0000000..0d7d5dd --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-c44f01.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-d61a15.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-d61a15.html new file mode 100644 index 0000000..5ffafa1 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-d61a15.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 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ed04ec.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ed04ec.html new file mode 100644 index 0000000..9a01ccb --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-ed04ec.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f2564c.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f2564c.html new file mode 100644 index 0000000..2dd83df --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f2564c.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f91718.html b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f91718.html new file mode 100644 index 0000000..1d23f81 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/report-f91718.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 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.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/sysprof-4 -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/cloudproviders -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/sysprof-4 -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/sysprof-4 -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/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -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/2021-08-03-190003-5771-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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/scanview.css b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/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/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/sorttable.js b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2021-08-03-190003-5771-1@5e28b06dc6ae_v1.26.0/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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/1.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/1.html new file mode 100644 index 0000000..1ba2312 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/1.html @@ -0,0 +1,999 @@ + + + + + + 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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/2.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/2.html new file mode 100644 index 0000000..47b52b6 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/2.html @@ -0,0 +1,713 @@ + + + + + + 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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/3.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/3.html new file mode 100644 index 0000000..0cd5670 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/3.html @@ -0,0 +1,335 @@ + + + + + + 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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/4.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/4.html new file mode 100644 index 0000000..0dbf85a --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/4.html @@ -0,0 +1,355 @@ + + + + + + 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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/5.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/5.html new file mode 100644 index 0000000..e9471f4 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/5.html @@ -0,0 +1,341 @@ + + + + + + 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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/6.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/6.html new file mode 100644 index 0000000..9f1f1a6 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/6.html @@ -0,0 +1,1329 @@ + + + + + + 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 'dir<=11' is not redundant<--- Assuming that condition '349<=dir' is not redundant
+        info->wind = WIND_N;
+    else if ((12 <= dir) && (dir <= 33))<--- Condition '12<=dir' is always true
+        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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/7.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/7.html new file mode 100644 index 0000000..449d61f --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/7.html @@ -0,0 +1,881 @@ + + + + + + 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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/8.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/8.html new file mode 100644 index 0000000..54b1514 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/8.html @@ -0,0 +1,3565 @@ + + + + + + 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
/* -*- 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_new ();
+    }
+
+    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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/index.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/index.html new file mode 100644 index 0000000..0c36689 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/index.html @@ -0,0 +1,157 @@ + + + + + + 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-metar.c
117knownConditionTrueFalse571styleCondition '12<=dir' is always true
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.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.
699variableScope398styleThe scope of the variable 'utf8' can be reduced.
699variableScope398styleThe scope of the variable 'timeformat' can be reduced.
717unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),timeformat,&tm)' is less than zero.
1072unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
1093unsignedLessThanZero570styleChecking if unsigned expression 'strftime(buf,sizeof(buf),mateweather_gettext("%H:%M"),&tm)' is less than zero.
+
+
+ + + diff --git a/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/stats.html b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/stats.html new file mode 100644 index 0000000..bbb6703 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/stats.html @@ -0,0 +1,116 @@ + + + + + + Cppcheck - HTML report - libmateweather + + + + + + +
+ +
+

Top 10 files for warning severity, total findings: 1
+   1  libmateweather/weather.c
+

+

Top 10 files for style severity, total findings: 25
+   7  libmateweather/weather.c
+   5  libmateweather/weather-metar.c
+   5  libmateweather/test_sun_moon.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/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/style.css b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/style.css new file mode 100644 index 0000000..07125f4 --- /dev/null +++ b/2021-08-03-190114-8453-cppcheck@5e28b06dc6ae_v1.26.0/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..8e9238d --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ + + + + + libmateweather Code Analyzer results + + +

+ mate-desktop/libmateweather Static analyzer results +

+ GitHub + Build Status +
+Commit: 5e28b06dc6ae3c3e1f2412c13d97eb5f6b91a9bf
+Compare:
+Branch: v1.26.0
+Time: 2021-08-03 19:01:14+00:00
+Messages:
+
+release 1.26.0
+
+
+ + + -- cgit v1.2.1