diff --git a/src/Makefile.am b/src/Makefile.am index 6cafd71..6e845a4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = calcelestial -calcelestial_SOURCES = calcelestial.c objects.c helpers.c +calcelestial_SOURCES = calcelestial.c objects.c helpers.c formatter.c calcelestial_LDADD = -lm -lnova if GEONAMES_SUPPORT diff --git a/src/Makefile.in b/src/Makefile.in index 68c3eea..5d4a652 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -66,10 +66,10 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am__calcelestial_SOURCES_DIST = calcelestial.c objects.c helpers.c \ - geonames.c + formatter.c geonames.c @GEONAMES_SUPPORT_TRUE@am__objects_1 = geonames.$(OBJEXT) am_calcelestial_OBJECTS = calcelestial.$(OBJEXT) objects.$(OBJEXT) \ - helpers.$(OBJEXT) $(am__objects_1) + helpers.$(OBJEXT) formatter.$(OBJEXT) $(am__objects_1) calcelestial_OBJECTS = $(am_calcelestial_OBJECTS) am__DEPENDENCIES_1 = @GEONAMES_SUPPORT_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) @@ -187,7 +187,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -calcelestial_SOURCES = calcelestial.c objects.c helpers.c \ +calcelestial_SOURCES = calcelestial.c objects.c helpers.c formatter.c \ $(am__append_1) calcelestial_LDADD = -lm -lnova $(am__append_2) @GEONAMES_SUPPORT_TRUE@geonames_SOURCES = geonames_main.c geonames.c @@ -284,6 +284,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/calcelestial.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/formatter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geonames.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geonames_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helpers.Po@am__quote@ diff --git a/src/calcelestial.c b/src/calcelestial.c index 94d78a6..f1e3a8c 100644 --- a/src/calcelestial.c +++ b/src/calcelestial.c @@ -43,12 +43,13 @@ #include "../config.h" #include "objects.h" #include "helpers.h" +#include "formatter.h" -enum mode { - MODE_NOW, - MODE_RISE, - MODE_SET, - MODE_TRANSIT +enum moment { + MOMENT_NOW, + MOMENT_RISE, + MOMENT_SET, + MOMENT_TRANSIT }; extern long timezone; @@ -70,9 +71,9 @@ static struct option long_options[] = { {0} }; -static char *long_options_descs[] = { - "calculate for given object/planet", - "calculate rise/set with given twilight (nautic|civil|astronomical)", +static const char *long_options_descs[] = { + "calculate for given object/planet (sun, moon, uranus, ...)", + "calculate rise/set with given twilight (nautic, civil, astronomical)", "calculate with given time (eg. 2011-12-25)", "use rise/set/transit time for position calculation", "output format (see strftime (3))", @@ -86,7 +87,7 @@ static char *long_options_descs[] = { "show version" }; -void version () { +void version() { printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); printf("libnova %s\n", LIBNOVA_VERSION); } @@ -96,7 +97,7 @@ void usage() { printf("Options:\n"); struct option *op = long_options; - char **desc = long_options_descs; + const char **desc = long_options_descs; while (op->name && desc) { printf(" -%c, --%s%s%s\n", op->val, op->name, (strlen(op->name) <= 7) ? "\t\t" : "\t", *desc); op++; @@ -110,17 +111,18 @@ void usage() { int main(int argc, char *argv[]) { /* default options */ double horizon = LN_SOLAR_STANDART_HORIZON; /* 50 Bogenminuten; no twilight, normal sunset/rise */ - char *format = "%H:%M:%S"; + char *format = "%Y-%m-%d %H:%M:%S"; char *query = NULL; bool error = false; - - enum mode mode = MODE_NOW; - enum object obj = OBJECT_INVALID; + bool verbose = false; double jd; - struct tm date = { 0 }; - struct ln_rst_time rst; + + enum moment moment = MOMENT_NOW; + enum object obj = OBJECT_INVALID; + struct ln_lnlat_posn obs = { DBL_MAX, DBL_MAX }; + struct object_details result; tzset(); @@ -132,8 +134,7 @@ int main(int argc, char *argv[]) { /* parse command line arguments */ while (1) { - int optidx; - int c = getopt_long(argc, argv, "+hvt:d:f:a:o:q:z:p:", long_options, &optidx); + int c = getopt_long(argc, argv, "+hvt:d:f:a:o:q:z:p:m:H:", long_options, NULL); /* detect the end of the options. */ if (c == -1) break; @@ -150,34 +151,35 @@ int main(int argc, char *argv[]) { horizon = LN_SOLAR_ASTRONOMICAL_HORIZON; } else { - fprintf(stderr, "invalid twilight: %s\n", optarg); - error = true; + char *endptr; + horizon = strtod(optarg, &endptr); + + if (endptr == optarg) { + fprintf(stderr, "invalid twilight: %s\n", optarg); + error = true; + } } break; case 't': - if (strptime(optarg, "%Y-%m-%d", &date) == NULL) { - fprintf(stderr, "invalid date: %s\n", optarg); - error = true; - } - else { - time_t t = mktime(&date); - jd = ln_get_julian_from_timet(&t); - -#ifdef DEBUG - char date_str[64]; - strftime(date_str, 64, "%Y-%m-%d", &date); - printf("parsed date: %s\n", date_str); -#endif - + { + struct tm date; + if (strptime(optarg, "%Y-%m-%d %H:%M:%S", &date) == NULL) { + fprintf(stderr, "invalid date: %s\n", optarg); + error = true; + } + else { + time_t t = mktime(&date); + jd = ln_get_julian_from_timet(&t); + } } break; case 'm': - if (strcmp(optarg, "now") == 0) mode = MODE_NOW; - else if (strcmp(optarg, "rise") == 0) mode = MODE_RISE; - else if (strcmp(optarg, "set") == 0) mode = MODE_SET; - else if (strcmp(optarg, "transit") == 0) mode = MODE_TRANSIT; + if (strcmp(optarg, "now") == 0) moment = MOMENT_NOW; + else if (strcmp(optarg, "rise") == 0) moment = MOMENT_RISE; + else if (strcmp(optarg, "set") == 0) moment = MOMENT_SET; + else if (strcmp(optarg, "transit") == 0) moment = MOMENT_TRANSIT; else { fprintf(stderr, "invalid moment: %s\n", optarg); error = true; @@ -256,7 +258,6 @@ int main(int argc, char *argv[]) { } #ifdef DEBUG -{ char date_str[64]; time_t t; ln_get_timet_from_julian(jd, &t); @@ -268,56 +269,25 @@ int main(int argc, char *argv[]) { printf("for object: %d\n", obj); printf("with horizon: %f\n", horizon); printf("with timezone: UTC +%dh\n", timezone / -3600); -} #endif - if (object_rst(obj, jd, horizon, &obs, &rst) == 1) { - - fprintf(stderr, "object is circumpolar\n"); - return EXIT_CIRCUMPOLAR; - } - - switch (mode) { - case MODE_NOW: jd = jd; break; /* use given (current) date */ - case MODE_RISE: jd = rst.rise; break; - case MODE_SET: jd = rst.set; break; - case MODE_TRANSIT: jd = rst.transit; break; - } - - // calculate position - struct object_details result; - - object_pos(obj, jd, &obs, &result); - - struct ln_hms ra; - ln_deg_to_hms(result.equ.ra, &ra); - - double az = result.hrz.az + 180; - az -= (int) (az / 360) * 360; - - char date_str[64]; - - printf("diam = %f\n", result.diameter); - printf("dist = %f au\n", result.distance); - printf("dist = %f km\n", AU_METERS * result.distance); - printf("az = %s\n", ln_get_humanr_location(az)); - printf("alt = %s\n", ln_get_humanr_location(result.hrz.alt)); - printf("ra = %dh%dm%fs\n", ra.hours, ra.minutes, ra.seconds); - printf("dec = %s\n", ln_get_humanr_location(result.equ.dec)); - printf("rise = %s\n", strfjd(date_str, sizeof(date_str), "%H:%M:%S", rst.rise)); - printf("set = %s\n", strfjd(date_str, sizeof(date_str), "%H:%M:%S", rst.set)); - printf("transit = %s\n", strfjd(date_str, sizeof(date_str), "%H:%M:%S", rst.transit)); - printf("daytime = %s\n", strfjddur(date_str, sizeof(date_str), "%H:%M:%S", rst.set - rst.rise)); - printf("nighttime = %s\n", strfjddur(date_str, sizeof(date_str), "%H:%M:%S", rst.rise - rst.set)); - - /*if (strstr(format, "%R") != NULL) { - snprintf(timestamp_str, sizeof(timestamp_str), "%lu", seconds); - format = strreplace(format, "%s", timestamp_str); + if (object_rst(obj, jd, horizon, &obs, &result.rst) == 1) { + if (moment != MOMENT_NOW) { + fprintf(stderr, "object is circumpolar\n"); + return EXIT_CIRCUMPOLAR; } - if (strstr(format, "%E") != NULL) { - snprintf(timestamp_str, sizeof(timestamp_str), "%lu", seconds); - format = strreplace(format, "%s", timestamp_str); - }*/ + } + else switch (moment) { + case MOMENT_NOW: result.jd = jd; break; + case MOMENT_RISE: result.jd = result.rst.rise; break; + case MOMENT_SET: result.jd = result.rst.set; break; + case MOMENT_TRANSIT: result.jd = result.rst.transit; break; + } + + result.obs = obs; + + object_pos(obj, result.jd, &obs, &result); + format_result(format, &result); return EXIT_SUCCESS; } diff --git a/src/formatter.c b/src/formatter.c new file mode 100644 index 0000000..cf713e9 --- /dev/null +++ b/src/formatter.c @@ -0,0 +1,79 @@ +/** + * Formatter + * + * @copyright 2012 Steffen Vogel + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @author Steffen Vogel + * @link http://www.steffenvogel.de/2012/03/14/cron-jobs-fur-sonnenauf-untergang/ + */ +/* + * This file is part of calcelestial + * + * calcelestial 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 3 of the License, or + * any later version. + * + * calcelestial 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 result. + * + * You should have received a copy of the GNU General Public License + * along with calcelestial. If not, see . + */ + +#include +#include +#include + +#include "objects.h" +#include "helpers.h" +#include "formatter.h" + +void format_result(const char *format, struct object_details *result) { + char buffer[128]; + char *local_format = strdup(format); + int i; + + struct ln_hms ra; + + /* convert results */ + ln_deg_to_hms(result->equ.ra, &ra); + ln_get_hrz_from_equ(&result->equ, &result->obs, result->jd, &result->hrz); + result->azidir = ln_hrz_to_nswe(&result->hrz); + result->hrz.az = ln_range_degrees(result->hrz.az + 180); + + struct specifiers specifiers[] = { + {"%J", &result->jd, DOUBLE}, + {"§r", &result->equ.ra, DOUBLE}, + {"§d", &result->equ.dec, DOUBLE}, + {"§a", &result->hrz.az, DOUBLE}, + {"§h", &result->hrz.alt, DOUBLE}, + {"§d", &result->diameter, DOUBLE}, + {"§e", &result->distance, DOUBLE}, + {"§t", &result->tz, INTEGER}, + {"§A", &result->obs.lat, DOUBLE}, + {"§O", &result->obs.lng, DOUBLE}, + {"§s", (void *) result->azidir, STRING}, + {"§§", "§", STRING}, + {0} + }; + + for (i = 0; specifiers[i].token; i++) { + if (strstr(local_format, specifiers[i].token) != NULL) { + switch (specifiers[i].format) { + case DOUBLE: snprintf(buffer, sizeof(buffer), "%." PRECISION "f", * (double *) specifiers[i].data); break; + case STRING: snprintf(buffer, sizeof(buffer), "%s", (char *) specifiers[i].data); break; + case INTEGER: snprintf(buffer, sizeof(buffer), "%d", * (int *) specifiers[i].data); break; + } + + local_format = strreplace(local_format, specifiers[i].token, buffer); + } + } + + strfjd(buffer, sizeof(buffer), local_format, result->jd); + printf("%s\n", buffer); + + free(local_format); +} diff --git a/src/formatter.h b/src/formatter.h new file mode 100644 index 0000000..17dda52 --- /dev/null +++ b/src/formatter.h @@ -0,0 +1,43 @@ +/** + * Formatter + * + * @copyright 2012 Steffen Vogel + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @author Steffen Vogel + * @link http://www.steffenvogel.de/2012/03/14/cron-jobs-fur-sonnenauf-untergang/ + */ +/* + * This file is part of calcelestial + * + * calcelestial 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 3 of the License, or + * any later version. + * + * calcelestial 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 calcelestial. If not, see . + */ + +#ifndef _FORMATTER_H_ +#define _FORMATTER_H_ + +#include + +#define PRECISION "3" + +enum specifier_fmt { DOUBLE, STRING, INTEGER }; + +struct specifiers { + const char *token; + void *data; + enum specifier_fmt format; +}; + +void format_result(const char *format, struct object_details *result); + +#endif /* _FORMATTER_H_ */ diff --git a/src/helpers.c b/src/helpers.c index 1bb2b16..7dd5339 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -81,7 +81,7 @@ char * strfjd(char *s, size_t max, const char *format, double jd) { return s; } -char * strreplace(char *subject, char *search, char *replace) { +char * strreplace(char *subject, const char *search, const char *replace) { int new_len = strlen(subject); int search_len = strlen(search); int replace_len = strlen(replace); diff --git a/src/helpers.h b/src/helpers.h index 653aa8d..b72c595 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -28,6 +28,6 @@ char * strfjddur(char *s, size_t max, const char *format, double jd); char * strfjd(char *s, size_t max, const char *format, double jd); -char * strreplace(char *subject, char *search, char *replace); +char * strreplace(char *subject, const char *search, const char *replace); #endif /* _HELPERS_H_ */ diff --git a/src/objects.c b/src/objects.c index 25b3ec7..5e3643e 100644 --- a/src/objects.c +++ b/src/objects.c @@ -75,7 +75,6 @@ enum object object_from_name(const char *name, bool casesen) { void object_pos_sun(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_solar_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_earth_solar_dist(jd); details->diameter = ln_get_solar_sdiam(jd); @@ -83,7 +82,6 @@ void object_pos_sun(double jd, struct ln_lnlat_posn *obs, struct object_details void object_pos_moon(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_lunar_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_lunar_earth_dist(jd) / AU_METERS; details->diameter = ln_get_lunar_sdiam(jd); @@ -91,7 +89,6 @@ void object_pos_moon(double jd, struct ln_lnlat_posn *obs, struct object_details void object_pos_mars(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_mars_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_mars_earth_dist(jd); details->diameter = ln_get_mars_sdiam(jd); @@ -99,7 +96,6 @@ void object_pos_mars(double jd, struct ln_lnlat_posn *obs, struct object_details void object_pos_neptune(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_neptune_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_neptune_earth_dist(jd); details->diameter = ln_get_neptune_sdiam(jd); @@ -107,7 +103,6 @@ void object_pos_neptune(double jd, struct ln_lnlat_posn *obs, struct object_deta void object_pos_jupiter(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_jupiter_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_jupiter_earth_dist(jd); details->diameter = ln_get_jupiter_equ_sdiam(jd); @@ -115,7 +110,6 @@ void object_pos_jupiter(double jd, struct ln_lnlat_posn *obs, struct object_deta void object_pos_mercury(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_mercury_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_mercury_earth_dist(jd); details->diameter = ln_get_mercury_sdiam(jd); @@ -123,7 +117,6 @@ void object_pos_mercury(double jd, struct ln_lnlat_posn *obs, struct object_deta void object_pos_uranus(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_uranus_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_uranus_earth_dist(jd); details->diameter = ln_get_uranus_sdiam(jd); @@ -131,7 +124,6 @@ void object_pos_uranus(double jd, struct ln_lnlat_posn *obs, struct object_detai void object_pos_saturn(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_saturn_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_saturn_earth_dist(jd); details->diameter = ln_get_saturn_equ_sdiam(jd); @@ -139,7 +131,6 @@ void object_pos_saturn(double jd, struct ln_lnlat_posn *obs, struct object_detai void object_pos_venus(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_venus_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_venus_earth_dist(jd); details->diameter = ln_get_venus_sdiam(jd); @@ -147,7 +138,6 @@ void object_pos_venus(double jd, struct ln_lnlat_posn *obs, struct object_detail void object_pos_pluto(double jd, struct ln_lnlat_posn *obs, struct object_details *details) { ln_get_pluto_equ_coords(jd, &details->equ); - ln_get_hrz_from_equ(&details->equ, obs, jd, &details->hrz); details->distance = ln_get_pluto_earth_dist(jd); details->diameter = ln_get_pluto_sdiam(jd); diff --git a/src/objects.h b/src/objects.h index 16ca179..6e41642 100644 --- a/src/objects.h +++ b/src/objects.h @@ -47,12 +47,18 @@ enum object { }; struct object_details { - struct ln_rst_time rst; /* rise/set/transit time in JD */ + double jd; /* julian date of observation */ + double tz; /* timezone of observer */ + + double diameter; /* in arc seconds */ + double distance; /* in AU */ + + struct ln_lnlat_posn obs; /* observer */ + struct ln_rst_time rst; /* rise/set/transit time in JD */ struct ln_equ_posn equ; struct ln_hrz_posn hrz; - double diameter; /* in arc seconds */ - double distance; /* in AU */ + const char *azidir; /* direction of azimuth - like N,S,W,E,NSW,.. */ }; enum object object_from_name(const char *name, bool casesen);