/* a clock. JosBoersema Oct-2000 (C) Copyright (C) 2001-2006 J.H. Boersema 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; version 2 of the License, or any later at your option. 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, write to the Free Software: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Oct2001 added options */ /* Sep2006 added options */ /* Compile on 2.2.17 Debian/Linux: gcc -lm -lncurses clockalrm.c */ /* Works with ncurses 5.x */ /* This code has not been optimised or anything like that. */ /* And it doesn't have a lot of comments :-(, sorry */ /* Testing: On a Debian system (at least), /usr/share/zoneinfo contains * files with local-time definitions; * % ln -s /usr/share/zoneinfo/ZONE /etc/localtime * changes the timezone to ZONE */ #include #include #include #include #include #include #include #include #define VERSION "1.05" #define SLEEP_SYSTIME_ERROR 2 #define REVERSE_VIDEO 0 #define SLEEP_SYSTIME_ERROR_STR "2" #define U_COLOR_HOUR 1 #define COLOR_HOUR COLOR_WHITE #define COLOR_HOUR_BG COLOR_BLACK #define U_COLOR_MIN 2 #define COLOR_MIN COLOR_WHITE #define COLOR_MIN_BG COLOR_BLACK #define U_COLOR_SEC 3 #define COLOR_SEC COLOR_RED #define COLOR_SEC_BG COLOR_BLACK #define U_COLOR_DEL 4 #define COLOR_DEL COLOR_BLACK #define COLOR_DEL_BG COLOR_BLACK #define COLOR_ALARM COLOR_GREEN #define COLOR_ALARM_BG COLOR_BLACK #define ERASE_VISIBLE '.' #define ERASE_INVISIBLE ' ' #define SEC_LENTH 120 #define MIN_LENGTH 120 #define HOUR_LENTH 60 #define PROG "clockalrm" #define USAGE_EXIT 1 #define SYSTIME_EXIT 2 #define PAST_EXIT 3 #define ERR_MKTIME_EXIT 4 #define ALT_SECOND 's' #define ALT_MINUTE 'm' #define ALT_HOUR 'H' #define SECOND_ARM 1 #define MINUTE_ARM 2 #define HOUR_ARM 3 #define PRINT_MODE_GRAPHIC 1 /* The character used for an arm changes during rotation */ #define PRINT_MODE_FIXED 2 /* The character used for an arm is fixed */ #define SEC_YEAR 31558118 /* Average number of seconds per year */ /* Alert: Globals ! (seems simpler right now then passing additional arguments) */ struct { time_t alrm ; time_t cntdwn ; char *txt ; short unlim ; /* Running without end (=1), or exit-time (=0) */ int off_y ; int off_x ; int max_y ; int max_x ; int min_y ; int min_x ; double width ; double hight ; signed short beat_terminal ; } glob_d = { 0 , 0 , "" , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } ; struct { char character_second ; /* character printed for second-arm */ char character_minute ; /* character printed for minute-arm */ char character_hour ; /* character printed for hour-arm */ char character_erase_sec ; /* character that erases second-arm */ short force_large ; /* always print clock big (1=always-big) */ short verbose ; /* Printing time in words, 0 is sometimes, 1 is never, 2 is always, 3 is short-format */ short reverse ; /* display count-back clock, bitmask * 0 0b00 nothing * 1 0b01 analogue * 2 0b10 digital * 3 0b11 both */ short second_arm_color ; /* colors for arms second arm */ short second_arm_color_bg ; short minute_arm_color ; short minute_arm_color_bg ; short hour_arm_color ; short hour_arm_color_bg ; short delete_arm_color ; short delete_arm_color_bg ; } appearance = { ALT_SECOND , ALT_MINUTE , ALT_HOUR , ERASE_INVISIBLE , 1 , 0 , 0 , COLOR_SEC , COLOR_SEC_BG , COLOR_MIN , COLOR_MIN_BG , COLOR_HOUR , COLOR_HOUR_BG , COLOR_DEL , COLOR_DEL_BG } ; short global_relative_gmt = 0 ; /* Times relative to UTC/GMT (=1), local-time (=0) */ void error_handler ( char * message , char * message2 , int value ) ; void usage_handler ( void ) ; void output_sec ( time_t sec , int print_mode ) ; void output_min ( time_t min , time_t sec , int print_mode ) ; void output_hour ( time_t hour , time_t min , int print_mode) ; int * get_screen_yx ( double fract , int base , int len) ; void sigwinch_handler ( int sig) ; void set_basic_screen ( void) ; void mvaddstr_draw ( int y , int x , int octant , int color , int type_arm , int mode) ; /* draws 1 character to the screen */ void sound_alarm ( short sec_arm_alarm_color , short sec_arm_alarm_color_bg , short sound ) ; char * sec1970_to_string ( time_t * sec1970) ; void output_medal ( void ) ; int main ( int argc , char * * argv ) { long signed zone_offs = 0 ; /* user defined zone-offset */ char * args_tmpp ; short sec_arm = 1 ; /* 1=second-arm, 0=no-second-arm */ int was_systime_error = 0 ; time_t sec1970 ; time_t secdiff ; struct tm * utsp ; int turns , i ; short init = 0 ; int delay = 1 ; long int time_tmp = 0 ; char print_mode = PRINT_MODE_FIXED ; /* default print-character-mode */ short print_am_pm = 0 ; /* Default for printing AM/PM */ short sec_arm_alarm_color = COLOR_ALARM ; /* Default color for second arm during alarm */ short sec_arm_alarm_color_bg = COLOR_ALARM_BG ; /* Default color for second arm during alarm */ short make_sound = 1 ; /* Default for making sound when alarm yes/no 1/0 */ char temp_string [ 31 ] ; /* Temporary space for writing misc strings */ short do_internal = 0 ; /* bitmask for internal/debugging things */ long signed cntdwn_offs = 0 , alrm_offs = 0 ; short watch_sim = 0 ; /* Print day name/number in wrist-watch style */ if ( -1== ( sec1970 = time ( 0 ) ) ) { error_handler ( "systime error" , "\n" , SYSTIME_EXIT ) ; } tzset ( ) ;/* initialize "timezone" variable */ signal ( SIGWINCH , sigwinch_handler ) ; if ( 1 < argc ) { char * temp_arg_p ; for ( i = 1 ; i < argc ; i ++ ) { /* pre-Process arguments: check for arguments that cause all times * to become interpreted relative to UTC/GMT rather then local time.*/ if ( 0 == strncmp ( "-u" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--utc" , * ( argv+i ) , 5 ) || 0 == strncmp ( "--gmt" , * ( argv+i ) , 5 ) ) { global_relative_gmt = 1 ; } } /* Process arguments */ for ( i = 1 ; i < argc ; i ++ ) { short do_usage_error = 0 ; if ( 0 == strncmp ( "-d" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--date" , * ( argv + i ) , 6 ) ) { struct tm tmp ; glob_d . unlim = 0 ; if ( 0 == strncmp ( "-d" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 7 ; } if ( 0 == global_relative_gmt ) { utsp = localtime ( & sec1970 ) ; } else { utsp = gmtime ( & sec1970 ) ; } /* Read user-given time into understandable struct tm */ if ( 0 == do_usage_error && 19 == strlen ( temp_arg_p ) ) { if ( '/' == * ( temp_arg_p + 2 ) ) { /* MONTH/DAY/YEAR HOUR:MIN:SEC */ tmp . tm_mon = strtol ( temp_arg_p , 0 , 10 ) - 1 ; tmp . tm_mday = strtol ( temp_arg_p + 3 , 0 , 10 ) ; tmp . tm_year = strtol ( temp_arg_p + 6 , 0 , 10 ) - 1900 ; tmp . tm_hour = strtol ( temp_arg_p + 11 , 0 , 10 ) ; tmp . tm_min = strtol ( temp_arg_p + 14 , 0 , 10 ) ; tmp . tm_sec = strtol ( temp_arg_p + 17 , 0 , 10 ) ; } else if ( '-' == * ( temp_arg_p + 2 ) ) { /* DAY-MONTH-YEAR HOUR:MIN:SEC */ tmp . tm_mday = strtol ( temp_arg_p , 0 , 10 ) ; tmp . tm_mon = strtol ( temp_arg_p + 3 , 0 , 10 ) - 1 ; tmp . tm_year = strtol ( temp_arg_p + 6 , 0 , 10 ) - 1900 ; tmp . tm_hour = strtol ( temp_arg_p + 11 , 0 , 10 ) ; tmp . tm_min = strtol ( temp_arg_p + 14 , 0 , 10 ) ; tmp . tm_sec = strtol ( temp_arg_p + 17 , 0 , 10 ) ; } else { /* YEAR.MONTH.DAY HOUR:MIN:SEC (default because most coherent format) */ tmp . tm_year = strtol ( temp_arg_p , 0 , 10 ) - 1900 ; tmp . tm_mon = strtol ( temp_arg_p + 5 , 0 , 10 ) - 1 ; tmp . tm_mday = strtol ( temp_arg_p + 8 , 0 , 10 ) ; tmp . tm_hour = strtol ( temp_arg_p + 11 , 0 , 10 ) ; tmp . tm_min = strtol ( temp_arg_p + 14 , 0 , 10 ) ; tmp . tm_sec = strtol ( temp_arg_p + 17 , 0 , 10 ) ; } } else if ( 0 == do_usage_error && 8 == strlen ( temp_arg_p ) ) { tmp . tm_year = ( * utsp ) . tm_year ; tmp . tm_mon = ( * utsp ) . tm_mon ; tmp . tm_mday = ( * utsp ) . tm_mday ; tmp . tm_hour = strtol ( temp_arg_p + 0 , 0 , 10 ) ; tmp . tm_min = strtol ( temp_arg_p + 3 , 0 , 10 ) ; tmp . tm_sec = strtol ( temp_arg_p + 6 , 0 , 10 ) ; } if ( 1 == ( do_internal & 0x1 ) ) { printf ( "%-10s: arg according to asctime(3) -> : %s" , PROG , asctime ( & tmp ) ) ; } if ( 1 == do_usage_error ) { error_handler ( "-d | --date requires date and time in one argument ( full year ) " , ", see -h\n" , USAGE_EXIT ) ; } if ( - 1 == ( glob_d . cntdwn = mktime ( & tmp ) ) ) { /* Where is the function which expects "UTC" ? */ error_handler ( "mktime(3) error" , ", could not make a time from arguments ( -h for usage ) \n" , ERR_MKTIME_EXIT ) ; } if ( 1 == ( do_internal & 0x1 ) ) { printf ( "%-10s: arg after mktime(3) call -> : %s" , PROG , asctime ( & tmp ) ) ; printf ( " -*-\n" ) ; } /* Trying to guess what UTC time belongs to the local-time * obtained from mktime(3), although mktime gives UTC time. */ if ( 1 == global_relative_gmt ) { /* Hoping this will undo the time-zone, which mktime(3) has * erroneously (from program standpoint) factored in, while * argument was UTC time. */ glob_d . cntdwn -= ( time_t ) timezone ; /* Trying to guess what mktime(3) has guessed about the * DST setting of its erroneously as local-time interpreted * UTC time argument */ utsp = localtime ( & glob_d.cntdwn ) ; /* Get DST setting of exit time */ if ( 0 < ( * utsp ) . tm_isdst ) {/* If DST-bug was active, remove */ glob_d . cntdwn += ( time_t ) 3600 ; } } } else if ( 0 == strncmp ( "-a" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--alarm" , * ( argv + i ) , 7 ) ) { if ( 0 == strncmp ( "-a" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i++; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 8 ; } if ( 1 == do_usage_error ) { error_handler ( "-a | --alarm requires an argument M:S" , ", see -h\n" , USAGE_EXIT ) ; } alrm_offs = strtol ( temp_arg_p , & args_tmpp , 10 ) * 60 ; alrm_offs += strtol ( args_tmpp + 1 , 0 , 10 ) ; glob_d . unlim = 0 ; } else if ( 0 == strncmp ( "-t" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--text" , * ( argv + i ) , 6 ) ) { if ( 0 == strncmp ( "-t" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 7 ; } if ( 1 == do_usage_error ) { error_handler ( "-t | --text requires an argument STRING",", see -h\n" , USAGE_EXIT ) ; } glob_d . txt = temp_arg_p ; } else if ( 0 == strncmp ( "-o" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--offset" , * ( argv + i ) , 8 ) ) { if ( 0 == strncmp ( "-o" , * ( argv+i ) , 2 ) ) { if ( i + 1 < argc ) { i++; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 9 ; } if ( 1 == do_usage_error ) { error_handler ( "-o | --offset requires an argument M:S" , ", see -h\n" , USAGE_EXIT ) ; } glob_d . unlim = 0 ; cntdwn_offs = abs ( strtol ( temp_arg_p , & args_tmpp , 10 ) * 60 ) ; cntdwn_offs += strtol ( args_tmpp + 1 , 0 , 10 ) ; if ( '-' == * temp_arg_p ) { cntdwn_offs = - cntdwn_offs ; } } else if ( 0 == strncmp ( "-u" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--utc" , * ( argv + i ) , 5 ) || 0 == strncmp ( "--gmt" , * ( argv + i ) , 5 ) ) { global_relative_gmt = 1 ; /* Times relative to UTC/GMT ( =1 ) , local-time ( =0 ) */ } else if ( 0 == strncmp ( "-Z" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--zero" , * ( argv + i ) , 5 ) || 0 == strncmp ( "--gmt" , * ( argv + i ) , 5 ) ) { /* A convenient way to get an upcounting clock. */ zone_offs = - sec1970 ; /* Clear offset to 0 seconds-since-Epoch `now'. */ global_relative_gmt = 1 ; /* Times relative to UTC/GMT ( =1 ) , local-time ( =0 ) */ } else if ( 0 == strncmp ( "-z" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--zone" , * ( argv + i ) , 6 ) ) { if ( 0 == strncmp ( "-z" , * ( argv+i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 7 ; } if ( 1 == do_usage_error ) { error_handler ( "-z | --zone requires an argument H:M:S" , ", see -h\n" , USAGE_EXIT ) ; } zone_offs = abs ( strtol ( temp_arg_p , & args_tmpp , 10 ) * 3600 ) ; zone_offs += strtol ( args_tmpp + 1 , & args_tmpp , 10 ) * 60; zone_offs += strtol ( args_tmpp + 1 , 0 , 10 ) ; if ( '-' == * temp_arg_p ) { zone_offs = - zone_offs ; } } else if ( 0 == strncmp ( "-C" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--countdown-digital" , * ( argv + i ) , 19 ) ) { glob_d . unlim = 0 ; appearance . reverse |= 0x2 ; /* Only digital reverse clock */ /* Use the space * `appearance.reverse > 0' as verbosity setting, * while ==0 is the `count-down appearance of * clock' boolean. Can not load it on * appearance.verbose, because this setting * is independent of that (may want to mix). */ } else if ( 0 == strncmp ( "-c" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--countdown" , * ( argv + i ) , 11 ) ) { glob_d . unlim = 0 ; appearance . reverse |= 0x1 ; /* Only analogue reverse clock */ } else if ( 0 == strncmp ( "-s" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--sleep" , * ( argv + i ) , 7 ) ) { if ( 0 == strncmp ( "-s" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 8 ; } if ( 1 == do_usage_error ) { error_handler ( "-s | --sleep requires an argument SECONDS" , ", see '-h\n'" , USAGE_EXIT ) ; } delay = ( int ) strtol ( temp_arg_p , 0 , 10 ) ; } else if ( 0 == strncmp ( "-n" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--no-sec-arm" , * ( argv + i ) , 12 ) ) { sec_arm = 0 ; } else if ( 0 == strncmp ( "-q" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--quotidian" , * ( argv + i ) , 11 ) ) { /* "quotidian" a) daily, b) of all days acc. lex. */ watch_sim = 1 ; } else if ( 0 == strncmp ( "-h" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--help" , * ( argv + i ) , 6 ) ) { usage_handler ( ) ; } /* ASCII-art mode for printing arms characters */ else if ( 0 == strncmp ( "-g" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--graphic" , * ( argv + i ) , 9 ) ) { print_mode = PRINT_MODE_GRAPHIC ; } /* ASCII-art mode for printing arms characters */ else if ( 0 == strncmp ( "-f" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--fixed" , * ( argv + i ) , 7 ) ) { print_mode = PRINT_MODE_FIXED ; } /* Foot steps left by second arm */ else if ( 0 == strncmp ( "-m" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--medal" , * ( argv + i ) , 6 ) ) { appearance . character_erase_sec = ERASE_VISIBLE ; appearance . delete_arm_color = COLOR_BLUE ; } /* Version */ else if ( 0 == strncmp ( "-v" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--version" , * ( argv + i ) , 9 ) ) { fprintf ( stdout , "%s %s\n" , PROG , VERSION ) ; exit ( 0 ) ; } /* Print AM|PM */ else if ( 0 == strncmp ( "-b" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--bell-no" , * ( argv + i ) , 9 ) ) { make_sound = 0 ; /* do not make sound */ } /* Print AM|PM */ else if ( 0 == strncmp ( "-x" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--am-pm" , * ( argv + i ) , 7 ) ) { print_am_pm = 1 ; } /* Set characters used for arms ... */ else if ( 0 == strncmp ( "-p" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--print" , * ( argv + i ) , 7 ) ) { if ( 0 == strncmp ( "-p" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 8 ; } if ( 1 == do_usage_error ) { error_handler ( "-p | --print requires an argument HMS" , ", see -h\n" , USAGE_EXIT ) ; } /* Below are some fun options shortcuts */ if ( 0 == strncmp ( "empty" , temp_arg_p , 5 ) ) { /* shorthand for use with colored arms */ /* Kind of usage error: trailing garbage `z' */ appearance . character_hour = ' ' ; appearance . character_minute = ' ' ; appearance . character_second = ' ' ; appearance . character_erase_sec = ' ' ; } else if ( 0 == strncmp ( "fizzz" , temp_arg_p , 5 ) ) { /* Wild looking, backdrop has some texture */ /* Kind of usage error: trailing garbage `z' */ appearance . character_hour = '@' ; appearance . character_minute = '^' ; appearance . character_second = ' ' ; appearance . character_erase_sec = 0x1F ; appearance . delete_arm_color = COLOR_GREEN ; } else if ( 0 == strncmp ( "knitted" , temp_arg_p , 7 ) ) { /* knitted sweater look */ appearance . character_hour = 'X' ; appearance . character_minute = 'X' ; appearance . character_second = 'X' ; appearance . character_erase_sec = 'X' ; appearance . second_arm_color = COLOR_YELLOW ; sec_arm_alarm_color = COLOR_YELLOW ; appearance . delete_arm_color = COLOR_RED ; if ( 0 == strncmp ( "knitted2" , temp_arg_p , 8 ) ) { /* different colors */ appearance . second_arm_color = COLOR_CYAN ; sec_arm_alarm_color = COLOR_CYAN ; appearance . delete_arm_color = COLOR_BLUE ; } } else if ( 0 == strncmp ( "nomedal" , temp_arg_p , 7 ) ) { /* shorthand for use with colored arms */ /* Kind of usage error: trailing garbage `z' */ appearance . delete_arm_color = COLOR_BLACK ; appearance . delete_arm_color_bg = COLOR_BLACK ; } else if ( 0 == strncmp ( "normal" , temp_arg_p , 6 ) ) { /* Reset to defaults, in case combinations of --print * cheatcodes change this in by user undesired ways. */ appearance . character_hour = 'H' ; appearance . character_minute = 'm' ; appearance . character_second = 's' ; appearance . character_erase_sec = ' ' ; } else if ( 0 == strncmp ( "shade" , temp_arg_p , 5 ) ) { /* Another quiet appearance, easier to see hour arm */ /* Kind of usage error: trailing garbage `z' */ appearance . character_hour = '\\' ; appearance . character_minute = '/' ; appearance . character_second = ' ' ; appearance . character_erase_sec = '/' ; appearance . delete_arm_color = COLOR_MAGENTA ; } else if ( 0 == strncmp ( "simple" , temp_arg_p , 6 ) ) { /* shorthand for use with colored arms */ /* Kind of usage error: trailing garbage `z' */ appearance . character_hour = ' ' ; appearance . character_minute = ' ' ; appearance . character_second = ' ' ; appearance . character_erase_sec = ' ' ; appearance . hour_arm_color = COLOR_BLUE ; appearance . hour_arm_color_bg = COLOR_GREEN ; appearance . minute_arm_color = COLOR_BLUE ; appearance . minute_arm_color_bg = COLOR_RED ; appearance . second_arm_color = COLOR_BLUE ; appearance . second_arm_color_bg = COLOR_MAGENTA ; sec_arm_alarm_color = COLOR_RED ; sec_arm_alarm_color_bg = COLOR_BLACK ; appearance . delete_arm_color = COLOR_BLACK ; appearance . delete_arm_color_bg = COLOR_BLUE ; } else if ( 0 == strncmp ( "terse" , temp_arg_p , 5 ) ) { /* Quiet clock */ /* Kind of usage error: trailing garbage `z' */ appearance . character_hour = '.' ; appearance . character_minute = '.' ; appearance . character_second = '.' ; appearance . character_erase_sec = ' ' ; appearance . second_arm_color = COLOR_BLUE ; } else if ( 0 == strncmp ( "wakeup" , temp_arg_p , 6 ) ) { /* This suddenly wakes up a dark terminal, flashing accross * a dark room. Keeps the second arm visible for orientation. */ appearance . character_hour = ' ' ; appearance . character_minute = ' ' ; appearance . character_second = ' ' ; appearance . character_erase_sec = ' ' ; appearance . hour_arm_color = COLOR_RED ; appearance . hour_arm_color_bg = COLOR_BLACK ; appearance . minute_arm_color = COLOR_RED ; appearance . minute_arm_color_bg = COLOR_BLACK ; appearance . second_arm_color = COLOR_BLACK ; appearance . second_arm_color_bg = COLOR_BLACK ; sec_arm_alarm_color = COLOR_BLACK ; sec_arm_alarm_color_bg = COLOR_MAGENTA ; appearance . delete_arm_color = COLOR_WHITE ; appearance . delete_arm_color_bg = COLOR_BLACK ; /* Keep terminal dark by default */ appearance . verbose = 1 ; /* never print time */ } else { appearance . character_hour = * ( temp_arg_p + 0 ) ; appearance . character_minute = * ( temp_arg_p + 1 ) ; appearance . character_second = * ( temp_arg_p + 2 ) ; if ( 0 != * ( temp_arg_p + 3 ) ) { /* not NULL end of string */ appearance . character_erase_sec = * ( temp_arg_p + 3 ) ; /* Reverse second arm: --print="O+ @" */ /* Same, with shade effect: --print="O+ ^X" ( Control-X ) */ } } } /* Force large printing of clock ... */ else if ( 0 == strncmp ( "-l",* ( argv + i ) , 2 ) || 0 == strncmp ( "--little" , * ( argv + i ) , 7 ) ) { appearance . force_large = 0 ; /* 1 = large , 0 = only large if no alarm */ } else if ( 0 == strncmp ( "-w" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--when-short" , * ( argv + i ) , 9 ) ) { appearance . verbose = 3 ; /* always print date/time , short format */ /* Printing alarm/exit time/date is also suppressed */ } else if ( 0 == strncmp ( "-W" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--when-full" , * ( argv + i ) , 10 ) ) { appearance . verbose = 2 ; /* always print date/time */ } else if ( 0 == strncmp ( "-0" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--when-no" , * ( argv + i ) , 9 ) ) { appearance . verbose = 1 ; /* never print time */ } /* Set seconds-arm color during alarm mode */ /* Keep this above --sec-color" */ else if ( 0 == strncmp ( "-K" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--sec-color-alarm" , * ( argv + i ) , 17 ) ) { if ( 0 == strncmp ( "-K" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv+i ) ; } else { temp_arg_p = * ( argv + i ) + 18 ; } /* Find color */ if ( 0 == strncmp ( "red" , temp_arg_p , 3 ) ) { sec_arm_alarm_color = COLOR_RED ; } else if ( 0 == strncmp ( "blue" , temp_arg_p , 4 ) ) { sec_arm_alarm_color = COLOR_BLUE ; } else if ( 0 == strncmp ( "green" , temp_arg_p , 5 ) ) { sec_arm_alarm_color = COLOR_GREEN ; } else if ( 0 == strncmp ( "yellow" , temp_arg_p , 6 ) ) { sec_arm_alarm_color = COLOR_YELLOW ; } else if ( 0 == strncmp ( "white" , temp_arg_p , 5 ) ) { sec_arm_alarm_color = COLOR_WHITE ; } else if ( 0 == strncmp ( "magenta" , temp_arg_p , 7 ) ) { sec_arm_alarm_color = COLOR_MAGENTA; } else if ( 0 == strncmp ( "cyan" , temp_arg_p , 4 ) ) { sec_arm_alarm_color = COLOR_CYAN ; } else if ( 0 == strncmp ( "black" , temp_arg_p , 5 ) ) { sec_arm_alarm_color = COLOR_BLACK ; } else { do_usage_error = 1 ; } if ( 1 == do_usage_error ) { error_handler ( "-K | --sec-color-alarm requires an argument COLOR" , ", see -h\n" , USAGE_EXIT ) ; } } /* Set seconds-arm color */ else if ( 0 == strncmp ( "-k" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--sec-color" , * ( argv + i ) , 11 ) ) { if ( 0 == strncmp ( "-k" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 12 ; } /* Find color */ if ( 0 == strncmp ( "red" , temp_arg_p , 3 ) ) { appearance . second_arm_color = COLOR_RED ; } else if ( 0 == strncmp ( "blue" , temp_arg_p , 4 ) ) { appearance . second_arm_color = COLOR_BLUE ; } else if ( 0 == strncmp ( "green" , temp_arg_p , 5 ) ) { appearance . second_arm_color = COLOR_GREEN ; } else if ( 0 == strncmp ( "yellow" , temp_arg_p , 6 ) ) { appearance . second_arm_color = COLOR_YELLOW ; } else if ( 0 == strncmp ( "white" , temp_arg_p , 5 ) ) { appearance . second_arm_color = COLOR_WHITE ; } else if ( 0 == strncmp ( "magenta" , temp_arg_p , 7 ) ) { appearance . second_arm_color = COLOR_MAGENTA ; } else if ( 0 == strncmp ( "cyan" , temp_arg_p , 4 ) ) { appearance . second_arm_color = COLOR_CYAN ; } else if ( 0 == strncmp ( "black" , temp_arg_p , 5 ) ) { appearance . second_arm_color = COLOR_BLACK ; } else { do_usage_error = 1 ; } if ( 1 == do_usage_error ) { error_handler ( "-k | --sec-color requires an argument COLOR" , ", see -h\n" , USAGE_EXIT ) ; } } /* Set all colors */ else if ( 0 == strncmp ( "-j" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--set-colors" , * ( argv + i ) , 12 ) ) { short break_out = 0 ; short * arg_color = NULL ; int arg_step = 1 ; if ( 0 == strncmp ( "-j" , * ( argv + i ) , 2 ) ) { if ( i + 1 < argc ) { i ++ ; } else { do_usage_error = 1 ; } temp_arg_p = * ( argv + i ) ; } else { temp_arg_p = * ( argv + i ) + 13 ; } /* Find color */ while ( 0 == break_out ) { /* Advance through all color definitions, create pointer to * the variable to change from the user argument */ switch ( arg_step ) { case 1 : arg_color = & appearance . hour_arm_color ; break ; case 2 : arg_color = & appearance . hour_arm_color_bg ; break ; case 3 : arg_color = & appearance . minute_arm_color ; break ; case 4 : arg_color = & appearance . minute_arm_color_bg ; break ; case 5 : arg_color = & appearance . second_arm_color ; break ; case 6 : arg_color = & appearance . second_arm_color_bg ; break ; case 7 : arg_color = & sec_arm_alarm_color ; break ; case 8 : arg_color = & sec_arm_alarm_color_bg ; break ; case 9 : arg_color = & appearance . delete_arm_color ; break ; case 10 : arg_color = & appearance . delete_arm_color_bg ; break ; } arg_step ++ ; if ( 0 == strncmp ( "nop" , temp_arg_p , 3 ) ) { ; /* do not change */ } else if ( 0 == strncmp ( "red" , temp_arg_p , 3 ) ) { * arg_color = COLOR_RED ; } else if ( 0 == strncmp ( "blue" , temp_arg_p , 4 ) ) { * arg_color = COLOR_BLUE ; } else if ( 0 == strncmp ( "green" , temp_arg_p , 5 ) ) { * arg_color = COLOR_GREEN ; } else if ( 0 == strncmp ( "yellow" , temp_arg_p , 6 ) ) { * arg_color = COLOR_YELLOW ; } else if ( 0 == strncmp ( "white" , temp_arg_p , 5 ) ) { * arg_color = COLOR_WHITE ; } else if ( 0 == strncmp ( "magenta" , temp_arg_p , 7 ) ) { * arg_color = COLOR_MAGENTA ; } else if ( 0 == strncmp ( "cyan" , temp_arg_p , 4 ) ) { * arg_color = COLOR_CYAN ; } else if ( 0 == strncmp ( "black" , temp_arg_p , 5 ) ) { * arg_color = COLOR_BLACK ; } else { do_usage_error = 1 ; break ; } /* Advance pointer to next argument */ while ( ',' != * temp_arg_p ) { if ( '\0' == * temp_arg_p ) { break_out = 1 ; break ; } else { temp_arg_p ++ ; } } temp_arg_p ++ ; } if ( 1 == do_usage_error ) { error_handler ( "-j | --set-colors requires an argument COLOR[,COLOR[,COLOR[...]]" , ", see -h\n" , USAGE_EXIT ) ; } } // else if ( 0 == strncmp ( "-e" , * ( argv + i ) , 2 ) || 0 == strncmp ( "--exit" , * ( argv + i ) , 6 ) ) { do_internal |= 0x1 ; /* Set last bit */ } else { error_handler ( * ( argv + i ) , " :unrecognized option , see -h\n" , USAGE_EXIT ) ; } } } /* Compute exit offset */ if ( 0 == glob_d . unlim ) { if ( - 1 == ( time_tmp = time ( 0 ) ) ) { error_handler ( "systime error" , "\n" , SYSTIME_EXIT ) ; } if ( 0 == glob_d . cntdwn ) { /* Set count-down to present moment */ glob_d . cntdwn = time_tmp + zone_offs ; } glob_d . cntdwn += cntdwn_offs ; glob_d . alrm = glob_d . cntdwn - alrm_offs ; if ( sec1970 + zone_offs > glob_d . cntdwn ) { time_t current_time ; /* Better error message */ current_time = sec1970 + zone_offs ; fprintf ( stderr , PROG ": current time: %s" , sec1970_to_string ( & current_time ) ) ; error_handler ( "value in the past: " , sec1970_to_string ( & glob_d . cntdwn ) , PAST_EXIT ) ; } } if ( 1 == ( do_internal & 0x1 ) ) { printf ( "%-10s: current time in seconds -> : %ld\n" , PROG , ( long ) sec1970 ) ; printf ( "%-10s: printed as -> : %s" , PROG , sec1970_to_string ( & sec1970 ) ) ; printf ( "%-10s: time according to localtime(3): %s" , "..." , asctime ( localtime ( & sec1970 ) ) ) ; printf ( "%-10s: time according to gmtime(3) : %s" , "..." , asctime ( gmtime ( & sec1970 ) ) ) ; printf ( " -*-\n" ) ; printf ( "%-10s: end on second -> : %ld\n" , PROG , ( long ) glob_d . cntdwn ) ; printf ( "%-10s: printed as -> : %s" , PROG , sec1970_to_string ( & glob_d . cntdwn ) ) ; printf ( "%-10s: end according to localtime(3): %s" , "..." , asctime ( localtime ( & glob_d . cntdwn ) ) ) ; printf ( "%-10s: end according to gmtime(3) : %s" , "..." , asctime ( gmtime ( & glob_d . cntdwn ) ) ) ; return 0 ; } set_basic_screen ( ) ; do { if ( 1 == glob_d . beat_terminal ) { sigwinch_handler ( 0 ) ; output_medal ( ) ; glob_d . beat_terminal = 0 ; init = 0 ; } if ( 1 < init ) { sleep ( delay ) ; } else { init ++ ; } while ( - 1 == ( sec1970 = time ( 0 ) ) ) { /* Error handling , but stay alive */ mvaddstr ( glob_d . off_y - 1 , glob_d . off_x - 8 , "!GET TIME ERROR!" ) ; mvaddstr ( glob_d . off_y , glob_d . off_x - 12 , " ( retry every " SLEEP_SYSTIME_ERROR_STR " seconds ) " ) ; sleep ( SLEEP_SYSTIME_ERROR ) ; was_systime_error = 1 ; } if ( 1 == was_systime_error ) { if ( 0 == glob_d . unlim && sec1970 > glob_d . cntdwn ) { error_handler ( glob_d . txt , "\nCouldn't get systime , countdown elapsed.\n" , SYSTIME_EXIT ) ; } was_systime_error = 0 ; sigwinch_handler ( 0 ) ; } sec1970 += zone_offs ; /* User defined warp */ if ( 0 == global_relative_gmt ) { utsp = localtime ( & sec1970 ) ; } else { utsp = gmtime ( & sec1970 ) ; } secdiff = glob_d . cntdwn - sec1970 ; /* Time to go */ if ( 0 != ( appearance . reverse & 0x1 ) ) { /* print analogue count-down */ turns = ( int ) ( secdiff / 43200 ) ; /* 12 * 60^2 , 12 hour intervals */ utsp = gmtime ( & secdiff ) ; /* Print visual representation of multiple turns of 12 hour clock * to count-down */ move ( 0 , glob_d . off_x ) ; for ( i = 0 ; i < turns ; i ++ ) { mvaddch ( glob_d . min_y , glob_d . off_x + i , '<' ) ; } } if ( 1 == sec_arm ) { output_sec ( ( * utsp ) . tm_sec , print_mode ) ; } output_min ( ( * utsp ) . tm_min , ( * utsp ) . tm_sec , print_mode ) ; output_hour ( ( * utsp ) . tm_hour , ( * utsp ) . tm_min , print_mode ) ; /* Reset to "present time" , not `arm moving dummy time' */ if ( 0 != ( appearance . reverse & 0x1 ) ) { if ( 0 == global_relative_gmt ) { utsp = localtime ( & sec1970 ) ; } else { utsp = gmtime ( & sec1970 ) ; } } if ( 1 == print_am_pm ) { if ( ( * utsp ) . tm_hour < 12 ) { mvaddstr ( glob_d . min_y + 1 , glob_d . max_x - 4 , "AM" ) ; mvaddstr ( glob_d . max_y - 1 , glob_d . max_x - 4 , " " ) ; } else { mvaddstr ( glob_d . min_y + 1 , glob_d . max_x - 4 , " " ) ; mvaddstr ( glob_d . max_y - 1 , glob_d . max_x - 4 , "PM" ) ; } } if ( 2 == appearance . verbose || 3 == appearance . verbose || ( 0 == appearance . verbose && 0 == glob_d . unlim ) ) { /* This prints the current time in words */ if ( 1 == glob_d . unlim || 3 == appearance . verbose ) { /* unlimited run: print at bottom. When small printing time , also suppress alarm time/date. */ if ( 3 == appearance . verbose ) { /* Special format: small */ mvaddnstr ( glob_d . max_y , glob_d . min_x , sec1970_to_string ( & sec1970 ) + 11 , 8 ) ; } else { /* Normal wide format */ mvaddnstr ( glob_d . max_y , glob_d . min_x , sec1970_to_string ( & sec1970 ) , 24 ) ; } } else { /* Limited run: print higher , above alarm/exit times */ mvaddnstr ( glob_d . max_y - 2 , glob_d . min_x , sec1970_to_string ( & sec1970 ) , 24 ) ; } } if ( 0 != ( appearance . reverse & 0x2 ) ) {/* If digital countdown */ if ( 60 * 60 * 24 * 365 < secdiff ) { // larger then one year // This is a crude approximation of calender time. // But an exact measure of identical intervals... // The Earth' rotation isn't the best of time-keepers. // Exactly reproducing the year-difference according to calender // time is more difficult. The countdown is an exact representation // of seconds to count-down, where calender-time is an artistic // impression of the same. snprintf ( temp_string , 30 , " % 3li:%03i:%02i:%02i:%02i " , (long int ) ( secdiff / ( 60 * 60 * 24 * 365 ) ) , ( int ) ( ( secdiff % ( 60 * 60 * 24 * 365 ) ) / ( 60 * 60 * 24 ) ) , ( int ) ( ( secdiff % ( 60 * 60 * 24 ) ) / ( 60 * 60 ) ) , ( int ) ( ( secdiff % ( 60 * 60 ) ) / 60 ) , ( int ) ( secdiff % 60 ) ); } else if ( 60 * 60 * 24 < secdiff ) { /* larger then one day */ /* Copy from right above, excl. years argument */ snprintf ( temp_string , 30 , " %03i:%02i:%02i:%02i " , ( int ) ( secdiff / ( 60 * 60 * 24 ) ) , ( int ) ( ( secdiff % ( 60 * 60 * 24 ) ) / ( 60 * 60 ) ) , ( int ) ( ( secdiff % ( 60 * 60 ) ) / 60 ) , ( int ) ( secdiff % 60 ) ); } else { /* Copy from right above, excl. days argument */ snprintf ( temp_string , 30 , " %02i:%02i:%02i " , ( int ) ( secdiff / ( 60 * 60 ) ) , ( int ) ( ( secdiff % ( 60 * 60 ) ) / 60 ) , ( int ) ( secdiff % 60 ) ); } mvaddnstr ( glob_d . max_y , glob_d . max_x - 30 , temp_string , 30 ) ; /* Exception: for both --utc and local time modes: call gmtime() */ clrtoeol ( ) ; /* Remove garbage if any */ } /* Print alarm/exit date/time. This is printed continuously, to * prevent overwriting by clock in very small window */ if ( 0 == glob_d . unlim && 1 != appearance . verbose && 3 != appearance . verbose ) { /* if limited run , and not verbose supressed */ /* This prints the date of alarm and exit */ mvaddnstr ( glob_d . max_y - 1 , glob_d . min_x , sec1970_to_string ( & glob_d . alrm ) , 24 ) ; mvaddnstr ( glob_d . max_y , glob_d . min_x , sec1970_to_string ( & glob_d . cntdwn ) , 24 ) ; } if ( 1 == watch_sim ) { /* Print day-of-week-name and day-of-month number, wrist-watch style */ /* Get current date/time in string */ snprintf ( temp_string , 30 , "%s" , sec1970_to_string ( & sec1970 ) ) ; /* ... and print its needed sections ... the day of the week: */ mvaddnstr ( glob_d . off_y , glob_d . off_x + COLS / 5 , temp_string , 3 ) ; /* Print always as a single word, looks nicer */ if ( 9 < ( * utsp ) . tm_mday ) { /* 2 digits day-of-month */ mvaddnstr ( glob_d . off_y , glob_d . off_x + COLS / 5 + 3 , temp_string + 8 , 2 ) ; } else { /* 1 digit day-of-month */ mvaddnstr ( glob_d . off_y , glob_d . off_x + COLS / 5 + 3 , temp_string + 9 , 1 ) ; } } if ( 0 == glob_d . unlim && sec1970 >= glob_d . alrm ) { sound_alarm ( sec_arm_alarm_color , sec_arm_alarm_color_bg , make_sound ) ; } move ( glob_d . off_y , glob_d . off_x ) ; refresh ( ) ; } while ( 1 == glob_d . unlim || sec1970 < glob_d . cntdwn ) ; endwin ( ) ; return EXIT_SUCCESS ; } void sigwinch_handler ( int sig ) { clear ( ) ; refresh ( ) ; endwin ( ) ; set_basic_screen ( ) ; glob_d . beat_terminal = 1 ; } void set_basic_screen ( void ) { initscr ( ) ; curs_set ( 0 ) ; start_color ( ) ; init_pair ( U_COLOR_HOUR , appearance . hour_arm_color , appearance . hour_arm_color_bg ) ; init_pair ( U_COLOR_MIN , appearance . minute_arm_color , appearance . minute_arm_color_bg ) ; init_pair ( U_COLOR_SEC , appearance . second_arm_color , appearance . second_arm_color_bg ) ; init_pair ( U_COLOR_DEL , appearance . delete_arm_color , appearance . delete_arm_color_bg ) ; if ( 1 == appearance . force_large ) { glob_d . width = COLS / ( double ) 266.6 ; glob_d . off_x = ( int ) ( COLS / 2 ) ; } else { glob_d . width = COLS / ( double ) 400 ; glob_d . off_x = ( int ) ( COLS / 2 + 8 ) ; } glob_d . off_y = ( int ) ( LINES / 2 ) ; glob_d . max_y = LINES - 1 ; glob_d . max_x = COLS - 1 ; glob_d . min_y = 0 ; glob_d . min_x = 0 ; glob_d . hight = LINES / ( double ) 250 ; /* This prints the user-defined string from the command-line */ mvaddnstr ( glob_d . min_y , glob_d . min_x , glob_d . txt , strlen ( glob_d . txt ) ) ; return ; } void error_handler ( char * message , char * message2 , int value ) { endwin ( ) ; fprintf ( stderr , PROG ": %s%s" , message , message2 ) ; exit ( value ) ; } void usage_handler ( void ) { endwin ( ) ; fprintf ( stdout , "Clockalrm, usage: clockalrm [OPTION[S]]\n" "-a ... | --alarm=MIN[.SEC] alarm goes before termination, default 0:0\n" "-b | --bell-no no beeps\n" "-c | --countdown analogue countdown clock\n" "-C | --countdown-digital digital countdown\n" "-d ... | --date=DATE program termination\n" " DATE: YYYY.MM.DD.HH.MM.SS YEAR.MONTH.DAY\n" " DD-MM-YYYY.HH:MM:SS DAY-MONTH-YEAR\n" " MM/DD/YYYY.HH:MM:SS MONTH/DAY/YEAR\n" " HH:MM:SS Assume present day\n" "-e | --exit Print time perceptions, then exit (debugging)\n" "-f | --fixed use \"Hms\" to print arms\n" "-g | --graphic print arms ASCII-art style\n" "-h | --help usage\n" "-j ... | --set-colors=COLOR[...] Define comma-list of COLORS:\n" " HOUR-FG,HOUR-BG,MIN-FG,MIN-BG,SEC-FG,SEC-BG,ALARM-FG,ALARM-BG,BG-FG,BG-BG\n" " The COLOR can be: black,blue,cyan,green,magenta,nop,red,white,yellow\n" "-k ... | --sec-color=COLOR second arm color to black,blue,cyan,green,\n" " magenta,red,white,yellow\n" "-K ... | --sec-color-alarm=COLOR second arm color during alarm to black,blue,\n" " cyan,green,magenta,red,white,yellow\n" "-l | --little smaller clock\n" "-m | --medal clock background\n" "-n | --no-sec-arm don't print seconds arm\n" "-o ... | --offset=MIN[.SEC] offset to -d, or from `now' if no -d option\n" "-p ... | --print=123[4] characters for --fixed mode, 4 for background\n" " Cheats: empty,fizzz,knitted[2],nomedal,normal,shade,simple,terse,wakeup\n" "-q | --quotidian day in wrist-watch style\n" "-s ... | --sleep=SECONDS sleep between sampling time, default 1\n" "-t ... | --text=TEXT display text\n" "-u | --utc | --gmt display UTC/GMT\n" "-v | --version print version\n" "-w | --when-short print current time in HH:MM:SS format\n" "-W | --when-full always display time in words/numbers\n" "-0 | --when-no never display time in words/numbers\n" "-x | --am-pm display \"AM\"|\"PM\"\n" "-z ... | --zone=HH[.MM[.SS]] timezone\n" "-Z | --zero present is 1 Jan 1970 00:00:00\n" ) ; exit ( EXIT_SUCCESS ) ; } void output_sec ( time_t sec , int print_mode ) { static int last_sec = -1 ; int * yx , i ; int octant ; if ( -1 == last_sec ) { last_sec = sec ; return ; } for ( i = 0 ; SEC_LENTH > i ; i ++ ) { yx = get_screen_yx ( last_sec , 60 , i ) ; mvaddch ( * yx , * ( yx + 1 ) , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } octant = ( int ) ( ( ( double ) sec + 3.75 ) / 7.5 ) ; /* Write new arm */ for ( i = 0 ; SEC_LENTH > i ; i ++ ) { yx = get_screen_yx ( sec , 60 , i ) ; mvaddstr_draw ( * yx , * ( yx + 1 ) , octant , U_COLOR_SEC , SECOND_ARM , print_mode ) ; } last_sec = sec ; return ; } void output_min ( time_t min , time_t sec , int print_mode ) { static double last_min = -1 ; double fract_min ; int * yx , i ; int octant ; if ( -1 == last_min ) { last_min = min + sec / ( double ) 60 ;; return ; } for ( i = 0 ; MIN_LENGTH > i ; i ++ ) { yx = get_screen_yx ( last_min , 60 , i ) ; mvaddch ( * yx , * ( yx + 1 ) , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } fract_min = min + sec / ( double ) 60 ; octant = ( int ) ( ( fract_min + 3.75 ) / 7.5 ) ; for ( i = 0 ; MIN_LENGTH > i ; i ++ ) { yx = get_screen_yx ( fract_min , 60 , i ) ; mvaddstr_draw ( * yx , * ( yx + 1 ) , octant , U_COLOR_MIN , MINUTE_ARM , print_mode ) ; } last_min = fract_min ; return ; } void output_hour ( time_t hour , time_t min , int print_mode) { static double last_hour = -1 ; double fract_hour ; int * yx , i ; int octant ; if ( -1 == last_hour ) { last_hour = hour + min / ( double ) 60 ; return ; } for ( i = 0 ; HOUR_LENTH > i ; i ++ ) { yx = get_screen_yx ( last_hour , 12 , i ) ; mvaddch ( * yx , * ( yx + 1) , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } if ( 12 <= hour ) { hour -= 12 ; } fract_hour = hour + min / ( double ) 60 ; octant = ( int ) ( ( fract_hour + .75 ) / 1.5 ) ; for ( i = 0 ; HOUR_LENTH > i ; i ++ ) { yx = get_screen_yx ( fract_hour , 12 , i ) ; mvaddstr_draw ( * yx , * ( yx + 1 ) , octant , U_COLOR_HOUR , HOUR_ARM , print_mode ) ; } last_hour = fract_hour ; return ; } /* Paint background. This prints a lot of "erase arms", enough * to cover the whole background */ void output_medal ( void ) { int * yx , i , j ; int step ; /* Guessing how many arms to print, proportional to size of screen */ if ( LINES < COLS ) { step = COLS * 4 ; //trial&error } else { step = LINES * 4 ; } for ( j = 0 ; step > j ; j ++ ) { /* This draws an outer circle, furthest point of the arms */ yx = get_screen_yx ( j , step , MIN_LENGTH ) ; mvaddch ( * yx , * ( yx + 1 ) , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; /* This draws from that point, a straight line to the center of the * clock, insofar possible when only going up/down left/right */ if ( LINES / 2 > * ( yx ) ) { for ( i = * ( yx ) ; LINES / 2 >= i ; i ++ ) { mvaddch ( i , * ( yx + 1 ) , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } } else { for ( i = * ( yx ) ; LINES / 2 <= i ; i -- ) { mvaddch ( i , * ( yx + 1 ) , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } } if ( COLS / 2 > * ( yx + 1 ) ) { for ( i = * ( yx + 1 ) ; COLS / 2 >= i ; i ++ ) { mvaddch ( * ( yx ) , i , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } } else { for ( i = * ( yx + 1 ) ; COLS / 2 <= i ; i -- ) { mvaddch ( * ( yx ) , i , REVERSE_VIDEO | COLOR_PAIR ( U_COLOR_DEL ) | appearance . character_erase_sec ) ; } } } return ; } /* Give a x-y coordinate, given radial input coordinates */ int * get_screen_yx ( double fract , int base , int len ) { static signed int screen_yx [ 2 ] = { 0 } ; double tmp ; tmp = fract / ( double ) base * 6.2831853 ; * screen_yx = ( int) ( -cos ( tmp ) * len * glob_d . hight + glob_d . off_y ) ; * ( screen_yx + 1 ) = ( int ) ( sin ( tmp ) * len * glob_d . width + glob_d . off_x ) ; if ( glob_d . max_y < * screen_yx ) { * screen_yx = glob_d . max_y ; } if ( glob_d . max_x < * ( screen_yx + 1 ) ) { * ( screen_yx + 1 ) = glob_d . max_x ; } if ( glob_d . min_y > * screen_yx ) { * screen_yx = glob_d . min_y ; } if ( glob_d . min_x > * ( screen_yx + 1 ) ) { * ( screen_yx + 1 ) = glob_d . min_x ; } /* * This cleared a block for date/time. Because it can produce an ugly * edge, static exit/alarm date/times are now continuously printed. * *//* //DELETE if ( 0 == glob_d . unlim && * ( screen_yx + 1 ) <= glob_d . min_x + 23 && * screen_yx >= glob_d . max_y - 2 ) { * ( screen_yx + 1 ) = glob_d . min_x + 23 ; * screen_yx = glob_d . min_y - 2 ; } */ return screen_yx ; } void mvaddstr_draw ( int y , int x , int octant , int color , int type_arm , int mode ) { char print_char ; /* Select character to print differently for every part of the circle */ if ( PRINT_MODE_GRAPHIC == mode ) { switch ( octant ) { /* For every part of the circle , another character */ case 0 : print_char = '|' ; break ; case 1 : print_char = '/' ; break ; case 2 : print_char = '=' ; break ; case 3 : print_char = '\\' ; break ; case 4 : print_char = '|' ; break ; case 5 : print_char = '/' ; break ; case 6 : print_char = '=' ; break ; case 7 : print_char = '\\' ; break ; case 8 : print_char = '|' ; break ; default : print_char = appearance . character_erase_sec ; break ; } } else { /* if ( PRINT_MODE_FIXED == mode ) { */ /* Select a character to print depending on the arm */ switch ( type_arm ) { case SECOND_ARM : print_char = appearance . character_second ; break ; case MINUTE_ARM : print_char = appearance . character_minute ; break ; case HOUR_ARM : print_char = appearance . character_hour ; break ; default : print_char = appearance . character_erase_sec ; } } mvaddch ( y , x , REVERSE_VIDEO | COLOR_PAIR ( color ) | ( char ) print_char ) ; return ; } /* Sound the alarm , change color second arm */ void sound_alarm ( short sec_arm_alarm_color , short sec_arm_alarm_color_bg , short sound ) {//FIXME: these two color args should be put in the global struct... static char here_bool = 0 ; short swap_color ; if ( 0 == here_bool ) { appearance . second_arm_color = sec_arm_alarm_color ; appearance . second_arm_color_bg = sec_arm_alarm_color_bg ; set_basic_screen ( ) ; /* Need to re-initialize for color change.*/ } else { here_bool = 1 ; } /* This causes the background to blink: reversing its fore/back-ground * colors every pass */ swap_color = appearance . delete_arm_color ; appearance . delete_arm_color = appearance . delete_arm_color_bg ; appearance . delete_arm_color_bg = swap_color ; if ( 1 == sound ) { beep ( ) ; } } char * sec1970_to_string ( time_t * sec1970 ) { static struct tm time_insulated ; /* Use other memory, repeated calls * otherwise make things even more difficult */ if ( 0 == global_relative_gmt ) { return asctime ( localtime_r ( sec1970 , & time_insulated ) ) ; } else { return asctime ( gmtime_r ( sec1970 , & time_insulated ) ) ; } }