/*****************************************************************************/ /* */ /* wmtz.c */ /* Shows local time in different timezones + JD + Sidereal time + */ /* internet time + local date and time. */ /* */ /* Jan Lindblom <99jl@home.se> (http://www.geocities.com/~jl1n/) */ /* */ /* wmtz.c was derived from: */ /* */ /* wminet.c */ /* */ /* Multi-function system monitor */ /* Dave Clark (clarkd@skynet.ca) (http://www.neotokyo.org/illusion) */ /* Martijn Pieterse (pieterse@xs4all.nl) (http://windowmaker.mezaway.org) */ /* and Antoine Nulle (warp@xs4all.nl) (http://windowmaker.mezaway.org) */ /* */ /* This software is licensed through the GNU General Public Licence. */ /* Read the COPYING file for details. */ /* */ /*****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wmtz.xpm" #include "wmtz_mono.xpm" /* * Defines */ #define WMTZ_VERSION "0.7" #define CHAR_WIDTH 6 #define STRSIZE 10 #define LMST 1 #define GMST 0 #define ABOUT "xmessage -center -buttons \"Close\" \"WMTZ - Window Maker Time Zone dockapp v0.7 http://www.geocities.com/jl1n/wmtz/wmtz.html\"" /* * Typedefs */ typedef struct { char label[10]; /* Time zone designation */ int diff; /* Time zone diff. from UT in hours */ double epoch; /* Epoch (for JD) */ char tz[256]; /* TZ environment variable string */ } timezone_t; /* ...numbers of days to subtract from JD */ /* * Global variables */ timezone_t zone[6]; double longitude = 0.0; double latitude = 0.0; static struct tm *clk; char *pname; char *uconfig_file; char *config_file; char *defedit; char *month[12]; char *week_day[7]; char wmtz_mask_bits[64*64]; int wmtz_mask_width = 64; int wmtz_mask_height = 64; int mono = 0; extern char *tzname[2]; static char originalTZ[64]; /* * Function declarations */ void usage(void); void printversion(void); void BlitString(char *name, int x, int y); void wmtz_routine(int, char **); int ReadConfigInt(FILE *fp, char *setting, int *value); int ReadConfigString(FILE *fp, char *setting, char *value); int Read_Config_File(char *filename); void range(double *val, double ran); void siderealTime(double jde, int *result, int mode); double julianDay(int year, int month, double day, double hour, double minute, double second, int julian); int calendarDate(double jd, int *year, int *month, double *day); int handleJD(void); void errH(int printErrno, int exitCode, const char *msg, ...); void handleTheMenu(int but_stat); double jdn(time_t curtime); /*****************************************************************************\ |* main *| \*****************************************************************************/ int main(int argc, char *argv[]) { int i; char *envbuf; /* Store away the executable name for error messages */ if ( (pname = strrchr( argv[0], '/' )) == NULL ) pname = argv[0]; else pname++; /* Store away the TZ environment variable, if set */ if ( (envbuf = getenv("TZ")) != NULL ) { //Write TZ=envbuf into originalTZ (void) sprintf(originalTZ, "TZ=%s", envbuf); } else { // Set originalTZ to TZ erase TZ env. (void) sprintf(originalTZ, "TZ"); } /* Parse Command Line */ for (i=1; i (i+1)) { uconfig_file = strdup(argv[i+1]); if (uconfig_file == NULL) errH(1, 1, "strdup"); i++; } break; case 'e' : if (argc > (i+1)) { defedit = strdup(argv[i+1]); if (defedit == NULL) errH(1, 1, "strdup"); i++; } break; default: usage(); exit(0); break; } } } month[0] = "JAN"; month[1] = "FEB"; month[2] = "MAR"; month[3] = "APR"; month[4] = "MAY"; month[5] = "JUN"; month[6] = "JUL"; month[7] = "AUG"; month[8] = "SEP"; month[9] = "OUT"; month[10] = "NOV"; month[11] = "DEC"; week_day[0] = "SUNDAY "; week_day[1] = "MONDAY "; week_day[2] = "TUESDAY "; week_day[3] = "WEDNESDAY"; week_day[4] = "THURSDAY "; week_day[5] = "FRIDAY "; week_day[6] = "SATURDAY "; wmtz_routine(argc, argv); return 0; } /*****************************************************************************\ |* wmtz_routine - Creates the wmtz window. *| \*****************************************************************************/ void wmtz_routine(int argc, char **argv) { int j = 0,k = 0, hour = 0, i = 0; int sid[2], clicked = 0, but_stat = -1; double jd = 0; float swatch_beats; time_t curtime; time_t prevtime; char *home; char buf[64]; char blitstr[STRSIZE]; XEvent Event; if (mono) { fprintf(stderr, "Starting monochrome version.\n"); createXBMfromXPM(wmtz_mask_bits, wmtz_mono_xpm, wmtz_mask_width, wmtz_mask_height); openXwindow(argc, argv, wmtz_mono_xpm, wmtz_mask_bits, wmtz_mask_width, wmtz_mask_height); } else { createXBMfromXPM(wmtz_mask_bits, wmtz_master_xpm, wmtz_mask_width, wmtz_mask_height); openXwindow(argc, argv, wmtz_master_xpm, wmtz_mask_bits, wmtz_mask_width, wmtz_mask_height); } memset(&zone, 0, sizeof(zone)); AddMouseRegion(0, 5, 6, 58, 16); AddMouseRegion(1, 5, 16, 58, 26); AddMouseRegion(2, 5, 26, 58, 36); AddMouseRegion(3, 5, 36, 58, 46); AddMouseRegion(4, 5, 46, 58, 56); /* Read config file */ if (uconfig_file != NULL) { /* user-specified config file */ fprintf(stderr, "Using user-specified config file '%s'.\n", uconfig_file); config_file = strdup(uconfig_file); free(uconfig_file); Read_Config_File(config_file); } else { home = getenv("HOME"); config_file = malloc( strlen(home) + 9 ); if (config_file == NULL) errH(1, 1, "malloc"); sprintf(config_file, "%s/.wmtzrc", home); if (!Read_Config_File(config_file)) { /* Fall back to /etc/wmtzrc */ free(config_file); config_file = malloc( 12 ); if (config_file == NULL) errH(1, 1, "malloc"); sprintf(config_file, "/etc/wmtzrc"); fprintf(stderr, "Using /etc/wmtzrc as config file.\n"); Read_Config_File(config_file); } } RedrawWindow(); prevtime = time(0) - 1; while (1) { waitpid(0, NULL, WNOHANG); /* If wmtz have been mouse-clicked, show menu */ if ( clicked ) { BlitString("MENU: ", 5, (11*(0)) + 5); BlitString(" WMTZ ", 5, (11*(1)) + 5); BlitString(" CONFIG ", 5, (11*(2)) + 5); BlitString(" RESTART ", 5, (11*(3)) + 5); BlitString(" QUIT ", 5, (11*(4)) + 5); } else if ( (curtime = time(0)) > prevtime) { prevtime = curtime; /* Update the display */ for (j=1; j<6; j++) { /* Display empty line */ if (strncmp( zone[j].label, "xxx", 3) == 0 ) { BlitString(" ", 5, (11*(j-1)) + 5); } /* Display local day/mon/year */ else if (strncmp( zone[j].label, "DATE", 4) == 0 ) { clk = localtime(&curtime); while(clk->tm_year>99) clk->tm_year-=100; snprintf(blitstr, STRSIZE,"%s %02d.%02d", month[clk->tm_mon],clk->tm_mday,clk->tm_year); BlitString(blitstr, 5, (11*(j-1)) + 5); } /* Display local weekday */ else if (strncmp( zone[j].label, "WDAY", 4) == 0 ) { clk = localtime(&curtime); snprintf(blitstr, STRSIZE,"%s",week_day[clk->tm_wday]); BlitString(blitstr, 4, (11*(j-1)) + 5); } /* Display more precise internet time */ else if (strncmp( zone[j].label,"@", 1) == 0 ) { /* Calculate Internet time */ swatch_beats = (float)(((curtime+3600)%86400)/86.4); snprintf (blitstr, STRSIZE, "@:%7.3f", swatch_beats); BlitString (blitstr, 5, (11*(j-1)) + 5); } /* Display Julian Day Number */ else if (strncmp( zone[j].label, "JDN", 3) == 0 ) { clk = gmtime(&curtime); /* Calculate Julin Day Number */ jd = jdn(curtime) - zone[j].epoch; snprintf(blitstr, STRSIZE, "%10f", jd ); BlitString(blitstr, 5, (11*(j-1)) + 5); } /* Display Local Mean Sidereal Time */ else if (strncmp( zone[j].label, "LMST", 3) == 0 ) { clk = gmtime(&curtime); jd = jdn(curtime); siderealTime( jd, sid, LMST ); snprintf(blitstr, STRSIZE, "%s%02i.%02i","LST:", sid[0], sid[1]); BlitString(blitstr, 5, (11*(j-1)) + 5); } /* Display Greenwich Mean Sidereal Time */ else if (strncmp( zone[j].label, "GMST", 3) == 0 ) { clk = gmtime(&curtime); jd = jdn(curtime); siderealTime( jd, sid, GMST ); snprintf(blitstr, STRSIZE, "%s%02i.%02i","GST:", sid[0], sid[1]); BlitString(blitstr, 5, (11*(j-1)) + 5); } /* Display local time */ else if (strncmp( zone[j].label, "LOCAL", 5) == 0 ) { clk = localtime(&curtime); strncpy(buf, tzname[0], 3); for (k=0; k<3; k++) if (buf[k] == 0) buf[k] = ' '; buf[3] = ':'; buf[4] = 0; hour = clk->tm_hour; /* Print Label */ snprintf(blitstr, STRSIZE, "%s%02i.%02i",buf,hour,clk->tm_min); BlitString(blitstr, 5, (11*(j-1)) + 5); } /* Display time in specified time zone */ else if (strncmp( zone[j].label, "TZONE", 4) == 0 ) { putenv(zone[j].tz); tzset(); clk = localtime(&curtime); strncpy(buf, tzname[0], 3); for (k=0; k<3; k++) if (buf[k] == 0) buf[k] = ' '; buf[3] = ':'; buf[4] = 0; snprintf(blitstr, STRSIZE, "%s%02i.%02i", buf, clk->tm_hour, clk->tm_min); BlitString(blitstr, 5, (11*(j-1)) + 5); /* Reset TZ environment variable to old value */ putenv(originalTZ); } /* Display time in specified time zone without TZ env. var. */ else { clk = gmtime(&curtime); strncpy(buf, zone[j].label, 3); for (k=0; k<3; k++) if (buf[k] == 0) buf[k] = ' '; buf[3] = ':'; buf[4] = 0; hour = clk->tm_hour - zone[j].diff; if (hour > 23 ) hour -= 24; else if (hour < 0 ) hour += 24; /* Print Label */ snprintf(blitstr, STRSIZE, "%s%02i.%02i",buf,hour,clk->tm_min); BlitString(blitstr, 5, (11*(j-1)) + 5); } } } RedrawWindow(); /* X Events */ while (XPending(display)) { XNextEvent(display, &Event); switch (Event.type) { case Expose: RedrawWindow(); break; case DestroyNotify: XCloseDisplay(display); exit(0); break; case ButtonPress: i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); but_stat = i; break; case ButtonRelease: i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); if (but_stat == i && but_stat >= 0) { if ( clicked ) /* The menu is up */ { handleTheMenu(but_stat); clicked = 0; } else /* Show the menu instead of time */ { clicked = 1; } } but_stat = -1; break; } } usleep(10000); } } /*****************************************************************************\ |* handleTheMenu *| \*****************************************************************************/ void handleTheMenu(int but_stat) { char *editor; char *ed; switch( but_stat ) { case 0: execCommand(ABOUT); break; case 1: break; case 2: /* Figure out what editor to use */ if ( defedit == NULL ) { ed = getenv("XEDITOR"); if ( ed == NULL ) ed = "xedit"; } else { ed = defedit; } editor = malloc( strlen(ed)+strlen(config_file)+2 ); if ( editor == NULL ) errH(1, 1, "malloc"); sprintf(editor, "%s %s", ed, config_file); waitpid( execCommand(editor), NULL, 0 ); Read_Config_File(config_file); free(editor); break; case 3: Read_Config_File(config_file); break; case 4: exit(0); break; } return; } /*****************************************************************************\ |* ReadConfigSetting *| \*****************************************************************************/ int ReadConfigString(FILE *fp, char *setting, char *value) { char str[1024]; char buf[1024]; int i; int len; int slen; char *p=NULL; if (!fp) { return 0; } snprintf(str,1024, "%s=", setting); slen = strlen(str); fseek(fp, 0, SEEK_SET); while ( !feof(fp) ) { if (!fgets(buf, 512, fp)) break; len = strlen(buf); /* strip linefeed */ for (i=0; i!=len; i++) if (buf[i] == '\n') buf[i] = 0; /* printf("Scanning '%s'...\n", buf); */ if ( strncmp(buf, str, strlen(str)) == 0) { /* found our setting */ for(i=0; i!=slen; i++) if ( buf[i] == '=' ) { p=buf+i+1; strcpy(value, p); return 1; } } } return 0; } /*****************************************************************************\ |* ReadConfigInt *| \*****************************************************************************/ int ReadConfigInt(FILE *fp, char *setting, int *value) { char buf[1024]; if (ReadConfigString(fp, setting, (char *) &buf)) { *value = atoi(buf); return 1; } return 0; } /*****************************************************************************\ |* ReadConfigDouble *| \*****************************************************************************/ int ReadConfigDouble(FILE *fp, char *setting, double *value) { char buf[1024]; if (ReadConfigString(fp, setting, (char *) &buf)) { *value = atof(buf); return 1; } return 0; } /*****************************************************************************\ |* Read_Config_File *| \*****************************************************************************/ int Read_Config_File( char *filename ) { FILE *fp; char temp[253]; fp = fopen(filename, "r"); if (fp) { ReadConfigString(fp, "time1", zone[1].label); ReadConfigString(fp, "time2", zone[2].label); ReadConfigString(fp, "time3", zone[3].label); ReadConfigString(fp, "time4", zone[4].label); ReadConfigString(fp, "time5", zone[5].label); ReadConfigInt(fp, "utdiff1", &zone[1].diff); ReadConfigInt(fp, "utdiff2", &zone[2].diff); ReadConfigInt(fp, "utdiff3", &zone[3].diff); ReadConfigInt(fp, "utdiff4", &zone[4].diff); ReadConfigInt(fp, "utdiff5", &zone[5].diff); ReadConfigDouble(fp, "utdiff1", &zone[1].epoch); ReadConfigDouble(fp, "utdiff2", &zone[2].epoch); ReadConfigDouble(fp, "utdiff3", &zone[3].epoch); ReadConfigDouble(fp, "utdiff4", &zone[4].epoch); ReadConfigDouble(fp, "utdiff5", &zone[5].epoch); ReadConfigString(fp, "utdiff1", temp); sprintf(zone[1].tz, "TZ=%s", temp); ReadConfigString(fp, "utdiff2", temp); sprintf(zone[2].tz, "TZ=%s", temp); ReadConfigString(fp, "utdiff3", temp); sprintf(zone[3].tz, "TZ=%s", temp); ReadConfigString(fp, "utdiff4", temp); sprintf(zone[4].tz, "TZ=%s", temp); ReadConfigString(fp, "utdiff5", temp); sprintf(zone[5].tz, "TZ=%s", temp); ReadConfigDouble(fp, "longitude", &longitude); /* ReadConfigDouble(fp, "latitude", &latitude); */ fclose(fp); return 1; } else { errH(1, 0, "Unable to open %s", filename); return 0; } } /*****************************************************************************\ |* BlitString - Blits a string at given coordinates. *| \*****************************************************************************/ void BlitString(char *name, int x, int y) { int i; int c; int k; k = x; for (i=0; name[i]; i++) { c = toupper(name[i]); if (c >= 'A' && c <= 'Z') { /* its a letter */ c -= 'A'; copyXPMArea(c * CHAR_WIDTH, 74, CHAR_WIDTH, 8, k, y); k += CHAR_WIDTH; } else if ( c >= '0' && c <= ':') { c -= '0'; copyXPMArea(c * CHAR_WIDTH, 64, CHAR_WIDTH, 8, k, y); k += CHAR_WIDTH; } else if (c == ';') /* used as a slim ':' */ { copyXPMArea(60, 64, CHAR_WIDTH, 8, k, y); k += 4; } else if (c=='.') { copyXPMArea(115, 64, 4, 8, k, y); k += 4; } else if (c=='@') { copyXPMArea(108, 64, CHAR_WIDTH, 8, k, y); k += CHAR_WIDTH; } else /* print a ' ' */ { copyXPMArea(120, 64, CHAR_WIDTH, 8, k, y); k += CHAR_WIDTH; } } } /*****************************************************************************\ |* usage *| \*****************************************************************************/ void usage(void) { fprintf(stderr, "\nwmtz - shows local time around the world and more.\n"); fprintf(stderr, "See ~/.wmtzrc or /etc/wmtzrc for configuration.\n\n"); fprintf(stderr, "Usage:\n"); fprintf(stderr, " -display \n"); fprintf(stderr, " -e use specified editor\n"); fprintf(stderr, " -geometry +XPOS+YPOS initial window position\n"); fprintf(stderr, " -jd Julian<->Date conversion\n"); fprintf(stderr, " -c use specified config file\n"); fprintf(stderr, " -m start monochrome version\n"); fprintf(stderr, " -h this help screen\n"); fprintf(stderr, " -v print the version number\n"); fprintf(stderr, "\n"); } /*****************************************************************************\ |* printversion *| \*****************************************************************************/ void printversion(void) { fprintf(stderr, "wmtz v%s\n", WMTZ_VERSION); } /*****************************************************************************\ |* range - Put val in 0<->ran interval. *| \*****************************************************************************/ void range (double *val, double ran) { *val -= ran*floor(*val/ran); if (*val < 0) *val += ran; } /*****************************************************************************\ |* jdn - converts a time_t to Julian Day *| \*****************************************************************************/ double jdn(time_t curtime) { return (curtime/86400.0 + 2440587.5); } /*****************************************************************************\ |* siderealTime - Gives sidereal time from JD. *| \*****************************************************************************/ void siderealTime( double jde, int *result, int mode ) { double t, t2, t3, ts; t = (jde - 2451545.0)/36525.0; t2 = t*t; t3 = t2*t; /* Expression from "Astronomical Algorithms" by J. Meeus */ ts = 280.46061837 + 360.98564736629 * ( jde - 2451545.0 ) + 0.000387933 * t2 - t3/38710000.0; range( &ts, 360.0 ); ts /= 15.0; /* If local time add one hour for every 15 degree in longitude */ if ( mode == LMST ) { ts += longitude/15.0; } range( &ts, 24.0 ); result[0] = (int)ts; result[1] = (int)(60 *(ts - result[0])); } /*****************************************************************************\ |* julianDay - Gives JD from date. *| \*****************************************************************************/ double julianDay( int year, int month, double day, double hour, double minute, double second, int julian ) { int a, b, c, d; double jd; day = day + hour/24.0 + minute/1440.0 + second/86400.0; if ( month < 3 ) { year -= 1; month += 12; } /* If the date is a Julian calendar date, set julian to TRUE */ if ( julian ) { b = 0; } else /* If Gregorian calendar date, julian should be FALSE */ { a = year/100; b = 2 - a + a/4; } c = 365.25 * (year + 4716); d = 30.6001 * (month + 1); jd = c + d + day + b - 1524.5; return( jd ); } /*****************************************************************************\ |* calendarDate - Gives date from JD. Only Gregorian calendar dates. *| \*****************************************************************************/ int calendarDate( double jd, int *year, int *month, double *day ) { double a, b, frac, ij, alfa, beta, c, d, e, f; if ( jd < 0 ) return 0; jd += 0.5; ij = floor(jd); frac = jd - ij; if ( ij < 2299161 ) { a = ij; } else { alfa = floor((ij - 1867216.25)/36524.25); beta = floor(alfa/4); a = ij + 1 + alfa - beta; } b = a + 1524; c = floor((b - 122.1)/365.25); d = floor(365.25 * c); e = floor((b - d)/30.6001); f = floor(30.6001 * e); *day = b - d - f + frac; if (e < 14) *month = e - 1; else if (e == 14 || e == 15) *month = e - 13; else return 0; if (*month > 2) *year = c - 4716; else if (*month == 1 || *month == 2) *year = c - 4715; else return 0; return 1; } /*****************************************************************************\ |* handleJD *| \*****************************************************************************/ int handleJD( void ) { int conv, y, m, d, h, min, sec; double day, jd; printf(" 1 : Date to JD.\n 2 : JD to date.\n"); printf("Choose conversion (1 or 2): "); scanf("%d", &conv); if (conv == 1 ) { printf("Enter UT date with time (YYYY,MM,DD,hh:mm:ss): "); scanf("%d,%d,%d,%d:%d:%d", &y, &m, &d, &h, &min, &sec); printf("\nJulian Day: %f\n", julianDay( y, m, d, h, min, sec, 0 ) ); } else if (conv == 2) { printf("Enter Julian Day Number: "); scanf("%lf", &jd ); if ( !calendarDate( jd, &y, &m, &day ) ) { printf("Conversion error! Negative JD not allowed.\n"); return 0; } printf("\nGregorian date: %d-%2.2d-%2.4f\n", y, m, day); } else { printf("Invalid choice! Try again, please...\n"); handleJD(); } return 1; } /*****************************************************************************\ |* errH *| \*****************************************************************************/ void errH(int printErrno, int exitCode, const char *msg, ...) { int error = errno; va_list arg; char buf[2048]; /* Put the name of the program first */ buf[0] = 0; strcat(buf, pname); strcat(buf, ": "); va_start(arg, msg); vsprintf(buf+strlen(buf), msg, arg); if (printErrno) sprintf(buf+strlen(buf), ": %s", strerror(error)); strcat(buf, "\n"); fflush(stdout); fputs(buf, stderr); fflush(NULL); va_end(arg); if ( exitCode ) exit(exitCode); return; }