/* * * wmScoreBoard-0.30 (C) 2000 Todd Kuper ( takuper@worldnet.att.net ) * * - Shows current sports scores * * Based on code from: * wmWeather (C) 1999 courtesy of Mike Henderson (mghenderson@lanl.gov) * wmStock (C) 1999 courtesy of Matt Fischer (mfischer@umr.edu) * - thanks guys! * * 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, 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 (see the file COPYING); if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA * * * ToDo: * * - add more error checking * - optimize downloading by sharing sport files (?) * - add keypress to force download * * Changes: * * 0.10 - first release * 0.20 - perform fork/wait for executing download Perl script * - added Download and Online status LEDs * - added -site, -delay, -bc, -pc, -tc, -sc options * - use alarm signal instead of timers to initiate download * - a lot of code cleanup including separating code into functions * - changed mouse button behavior * 0.30 - team name and score drawing is smarter about knowing * how many characters they can draw * - ClearWindow function correcly wipes the window clean now * - improved reading of score file */ #include "wmscoreboard.h" #include "wmscoreboard_master.xpm" #include "wmscoreboard_mask.xbm" /* Global variables */ int OnlineStatus = ONLINE; int ForceUpdate = 0; int ForceDownload = 0; long DownloadDelay = 120; char DirName[256]; char Sport[12]; char Team[12]; char HomeName[12]; char VisitorsName[12]; char HomeScore[12]; char VisitorsScore[12]; char Period[12]; char Date[12]; char DownloadScript[35] = "GrabScores"; char Site[20] = "excite"; char BackColor[30] = "#000000"; char TeamColor[30] = "#00ff00"; char ScoreColor[30] = "#00ffff"; char PeriodColor[30] = "#ffff00"; /* Main */ int main( int argc, char* argv[] ) { /* Register my alarm signal */ signal( SIGALRM, AlarmHandler ); /* Check on the ~/.wmScoreBoard directory */ if ( CheckDir() == ERROR ) exit( ERROR ); /* Process the command line options */ if ( ParseCommandLine( argc, argv ) == ERROR ) exit( ERROR ); /* Initialize and open the window */ initXwindow( argc, argv ); openXwindow( argc, argv, wmscoreboard_master, wmscoreboard_mask_bits, wmscoreboard_mask_width, wmscoreboard_mask_height, BackColor, TeamColor, ScoreColor, PeriodColor ); /* Draw the window */ ClearWindow(); RedrawWindow(); PaintDownloadLED( IDLE ); PaintOnlineLED( OnlineStatus ); RedrawWindow(); alarm( 3 ); /* Set a short alarm */ /* Loop until we die */ while( 1 ) { /* Check to see if we need to download the score */ if ( ForceDownload && ( OnlineStatus == ONLINE ) ) { ForceDownload = 0; if ( DownloadScore() == ERROR ) { PaintDownloadLED( ERROR ); RedrawWindow(); } else { ForceUpdate = 1; } /* Reset the alarm */ alarm( DownloadDelay ); } /* Check to see if we need to update the window */ if ( ForceUpdate ) { ForceUpdate = 0; if ( ReadScore() == ERROR ) { PaintDownloadLED( ERROR ); RedrawWindow(); } else { ClearWindow(); PaintData(); PaintOnlineLED( OnlineStatus ); PaintDownloadLED( IDLE ); RedrawWindow(); } } /* Process any pending X events */ ProcessXEvents(); /* Sleep for awhile so we don't chew up all the CPU */ usleep( 10000 ); } } /* Process X events */ void ProcessXEvents( void ) { XEvent event; while ( XPending( display ) ) { XNextEvent( display, &event ); switch( event.type ) { case Expose: RedrawWindow(); break; case ButtonPress: ButtonPressEvent( &event.xbutton ); break; case KeyPress: KeyPressEvent( &event.xkey ); break; case EnterNotify: XSetInputFocus( display, PointerRoot, RevertToParent, CurrentTime ); break; case LeaveNotify: XSetInputFocus( display, PointerRoot, RevertToParent, CurrentTime ); break; default: break; } } } /* Download the scores */ int DownloadScore( void ) { int processID; int processStatus; PaintDownloadLED( DOWNLOADING ); RedrawWindow(); if ( ( processID = fork() ) < 0 ) { return ERROR; } /* The child process executes this */ if ( processID == 0 ) { execlp( DownloadScript, DownloadScript, Sport, Team, NULL ); exit( ERROR ); } /* The parent keeps checking to see if the child has terminated */ while ( !( waitpid( processID, &processStatus, WNOHANG ) ) ) { ProcessXEvents(); usleep( 10000 ); } /* Return an error if the child failed to execute correctly */ if ( WIFEXITED( processStatus ) == 0 || WEXITSTATUS( processStatus ) == ERROR ) { return ERROR; } return OK; } /* Read info from the appropriate scores file */ int ReadScore( void ) { int lineLength; char line[512], fileName[256]; FILE *fp; sprintf( fileName, "%s/score.%s.%s", DirName, Sport, Team ); if ( ( fp = fopen( fileName, "r" ) ) != NULL ) { lineLength = sizeof( line ); HomeName[0] = '\0'; fgets( line, lineLength, fp ); sscanf( line, "%11s", HomeName ); HomeScore[0] = '\0'; fgets( line, lineLength, fp ); sscanf( line, "%3s", HomeScore ); VisitorsName[0] = '\0'; fgets( line, lineLength, fp ); sscanf( line, "%11s", VisitorsName ); VisitorsScore[0] = '\0'; fgets( line, lineLength, fp ); sscanf( line, "%3s", VisitorsScore ); Period[0] = '\0'; fgets( line, lineLength, fp ); sscanf( line, "%11s", Period ); Date[0] = '\0'; fgets( line, lineLength, fp ); sscanf( line, "%11s", Date ); fclose(fp); } else { return ERROR; } return OK; } /* Draw the data text */ void PaintData( void ) { int i, col, maxCols = MAX_COLS; /* Leave enough room for the score */ if ( strlen( HomeScore ) > strlen( VisitorsScore ) ) { maxCols = 11 - strlen( HomeScore ) - 1; } else { maxCols = 11 - strlen( VisitorsScore ) - 1; } /* Paste data */ for ( i = 0; i < strlen( VisitorsName ) && i < maxCols; ++i ) { PasteChar( VisitorsName[i], 0, i, 1 ); } col = 10; for ( i = strlen( VisitorsScore ) - 1; i >= 0; --i ) { PasteChar( VisitorsScore[i], 1, col, 1 ); --col; } for ( i = 0; i < strlen( HomeName ) && i < maxCols; ++i ) { PasteChar( HomeName[i], 0, i, 2 ); } col = 10; for ( i = strlen( HomeScore ) - 1; i >= 0; --i ) { PasteChar( HomeScore[i], 1, col, 2 ); --col; } for ( i = 0; i < strlen( Period ) && i < MAX_COLS; ++i ) { PasteChar( Period[i], 2, i, 4 ); } for ( i = 0; i < strlen( Date ) && i < MAX_COLS; ++i ) { PasteChar( Date[i], 2, i, 5 ); } } /* Paint the Online LED with the appropriate color */ void PaintOnlineLED( int status ) { switch( status ) { case ONLINE: PasteLED( 0, 10, 7 ); break; case OFFLINE: PasteLED( 4, 10, 7 ); break; default: PasteLED( 1, 10, 7 ); break; } } /* Paint the Download LED with the appropriate color */ void PaintDownloadLED( int status ) { switch( status ) { case DOWNLOADING: PasteLED( 0, 9, 7 ); break; case IDLE: PasteLED( 1, 9, 7 ); break; case ERROR: PasteLED( 4, 9, 7 ); break; default: PasteLED( 1, 9, 7 ); break; } } /* Paste an LED to the window */ void PasteLED( int color, int col, int row ) { int dx, dy, x0, y0; dx = col * ( CHAR_WIDTH + HORIZONTAL_SPACING ) + HORIZONTAL_MARGIN; dy = row * ( CHAR_HEIGHT + VERTICAL_SPACING ) + VERTICAL_MARGIN; x0 = 65 + ( color * CHAR_WIDTH ); y0 = 58; copyXPMArea( x0, y0, CHAR_WIDTH, CHAR_HEIGHT, dx, dy ); } /* Paste one character to the window */ void PasteChar( char c, int color, int col, int row ) { char ascii; int x0 = 0, y0 = 0; int dx = 0, dy = 0; dx = col * ( CHAR_WIDTH + HORIZONTAL_SPACING ) + HORIZONTAL_MARGIN; dy = row * ( CHAR_HEIGHT + VERTICAL_SPACING ) + VERTICAL_MARGIN; ascii = (int)c; if ( ascii >= 65 && ascii <= 90 ) { x0 = CHAR_WIDTH * ( ascii - 65 ); y0 = 65; } else if ( ascii >= 48 && ascii <= 57 ) { x0 = CHAR_WIDTH * ( ascii - 48 ) + 65; y0 = 0; } else if ( ascii == 58 ) { x0 = 115; y0 = 0; } else { x0 = 120; y0 = 0; } y0 += color * ( CHAR_HEIGHT + 2 ); copyXPMArea( x0, y0, CHAR_WIDTH, CHAR_HEIGHT, dx, dy ); } /* Wipe the window clean */ void ClearWindow( void ) { copyXPMArea( 0, 110, 55, 55, HORIZONTAL_MARGIN, VERTICAL_MARGIN ); } /* * Handle button presses * * - Left mouse single click forces download * - Right mouse single click toggles online/offline status * */ void ButtonPressEvent( XButtonEvent *xev ) { if ( (xev->button == Button1 ) && ( xev->type == ButtonPress ) ) { ForceDownload = 1; } if ( (xev->button == Button3 ) && ( xev->type == ButtonPress ) ) { if ( OnlineStatus == ONLINE ) { OnlineStatus = OFFLINE; } else { OnlineStatus = ONLINE; } PaintOnlineLED( OnlineStatus ); RedrawWindow(); } } /* Handle key presses - stub */ void KeyPressEvent( XKeyEvent *xev ) { return; } /* Parse the command line for parameters and options */ int ParseCommandLine( int argc, char *argv[] ) { int i; long delay = 0; for ( i = 1; i < argc; i++ ) { if ( !strcmp( argv[i], "-display" ) ) { ++i; } else if ( !strcmp( argv[i], "-sport" ) ) { if ( ( i + 1 >= argc ) || ( argv[i + 1][0] == '-') ) { fprintf( stderr, "\nError: No sport symbol given for the -sport option\n" ); PrintUsage(); return ERROR; } strcpy( Sport, argv[++i] ); } else if ( !strcmp( argv[i], "-team" ) ) { if ( ( i + 1 >= argc ) || ( argv[i + 1][0] == '-') ) { fprintf( stderr, "\nError: No team symbol given for the -team option\n" ); PrintUsage(); return ERROR; } strcpy( Team, argv[++i] ); } else if ( !strcmp( argv[i], "-help" ) ) { PrintUsage(); return ERROR; } else if ( !strcmp( argv[i], "-site" ) ) { if ( (i + 1 >= argc ) || ( argv[i + 1][0] == '-' ) ) { fprintf( stderr, "\nError: No site name given for option -site\n" ); PrintUsage(); return ERROR; } strcpy( Site, argv[++i] ); } else if ( !strcmp( argv[i], "-delay" ) ) { if ( (i + 1 >= argc ) || ( argv[i + 1][0] == '-' ) ) { fprintf( stderr, "\nError: No time given for option -delay\n" ); PrintUsage(); return ERROR; } delay = strtol( argv[i + 1], NULL, 10 ); if ( delay < 1 || errno == ERANGE ) { fprintf( stderr, "\nError: Delay time %s is invalid\n", argv[i + 1] ); PrintUsage(); return ERROR; } DownloadDelay = delay; ++i; } else if ( !strcmp( argv[i], "-bc" ) ) { if ( (i + 1 >= argc ) || ( argv[i + 1][0] == '-' ) ) { fprintf( stderr, "\nError: No color found for option -bc\n" ); PrintUsage(); return ERROR; } strcpy( BackColor, argv[++i] ); } else if ( !strcmp( argv[i], "-tc" ) ) { if ( (i + 1 >= argc ) || ( argv[i + 1][0] == '-' ) ) { fprintf( stderr, "\nError: No color found for option -tc\n" ); PrintUsage(); return ERROR; } strcpy( TeamColor, argv[++i] ); } else if ( !strcmp( argv[i], "-sc" ) ) { if ( (i + 1 >= argc ) || ( argv[i + 1][0] == '-' ) ) { fprintf( stderr, "\nError: No color found for option -sc\n" ); PrintUsage(); return ERROR; } strcpy( ScoreColor, argv[++i] ); } else if ( !strcmp( argv[i], "-pc" ) ) { if ( (i + 1 >= argc ) || ( argv[i + 1][0] == '-' ) ) { fprintf( stderr, "\nError: No color found for option -pc\n" ); PrintUsage(); return ERROR; } strcpy( PeriodColor, argv[++i] ); } else { PrintUsage(); return ERROR; } } if ( strlen( Sport ) == 0 ) { fprintf( stderr, "\nError: You must specify a sport code\n" ); PrintUsage(); return ERROR; } if ( strlen( Team ) == 0 ) { fprintf( stderr, "\nError: You must specify a team code\n" ); PrintUsage(); return ERROR; } strcat( DownloadScript, "." ); strcat( DownloadScript, Site ); return OK; } /* Print the usage verbage */ void PrintUsage( void ) { printf( "\nwmScoreBoard\n" ); printf( "version: %s %s\n", WMSCOREBOARD_VERSION, WMSCOREBOARD_DATE ); printf("----------------------------------------------------------------------------\n"); printf( "Usage: wmScoreBoard -sport -team \n" ); printf( " [-display ] [-help] [-delay