/************************************************************************* * Copyright Xdel Technology Pty. Ltd. 1987 * Copyright (C) 1995 Embedded Solutions * All rights reserved * * file: src\upload.c * * purpose: Data upload functions * This module contains all the functions required to upload * data from the handheld calculators and insert the data * into the data base as well as functions and a menu to load * and unload specific data into the data base * * functions * upload - Get Leg to upload * ins_data - Insert time info into data base * supload - Extended upload functions menu * tupload - Read in text team information * t_parse_number - Parse a number from a CSV line of team text * t_parse_text - Parse string from a CSV line of team text * p_del - Test for a delimiter. * tdnload - Generate team name file * dnload - Generate leg timing file * getfname - Get a filename from the user * * programmer: David Purdie * * revision date by reason * May 1990 Margherita Veroni * The functions to upload data have been modified * to allow leg start times to also be uploaded for * any leg. Data being uploaded which contain errors * are written to an error file * * 00.0 1-Apr-94 DDP Changed tdnload() to produce a comma seperated * file. This allows external users to see the * field delimters better than tabs * * 00.0 27/01/95 DDP Tidies up the program and formatted the file * **************************************************************************/ #include #include "consts.h" #include "structs.h" #include "proto.h" /* Variable storage */ char ufilename[40]; /* Name of upload file */ FILE *ufile; /* Upload file stream */ FILE *efile; /* Error file stream */ char line[300]; /* Input line */ char line_text[133]; /* Output text */ unsigned char manstart; /* Manual start time entry */ menu_table sup_menu[] = { { '1', "Load team information from external file", tupload }, { '2', "Create external team information file", tdnload }, { '3', "Create external leg data file", dnload }, { '4', "Upload time information", upload }, { 'q', "Return to main menu", 0 }, { '\0' } }; /*======================================================================== * * Get Leg to upload * * Purpose: * This function is called to Get Leg to upload * Prompt user for leg number and start / end of leg * Open disc file * Read and parse text. Enter data into team information * Maintain error file of errors. * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void upload(void) { int hh, mm, ss; /* Team times */ int error = 0; /* Count of errors */ int ntms = 0; /* Number of teams uploaded */ char stend[] = "E"; /* Start or End time */ char *filename; /* Name of file to open */ char *err_filename; /* Name of an error file to open */ cur( 0, 5 ); while( TRUE ) { leg = 0; d_field( 0, 6, "Enter leg to upload :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - Exit loop */ break; beep(); /* Make a noise and wait for valid number */ } /* * Find out if Start or End of leg times to be uploaded */ do { d_field( 0, 7, "Start or End of leg to upload :", D_USTRING, 1, stend, TRUE, M_UPDATE ); } while( ( stend[0] != 'S' ) && ( stend[0] != 'E' ) ); manstart = ( ( stend[0] == 'S' ) ? TRUE : FALSE ); printf( "\n" ); /* * Locate the required data file and prepare for processing */ filename = tprintf( "%s%d" , manstart ? "Sleg" : "leg" , leg ); ufile = fopen( filename, "rt" ); if( ufile == 0 ) { printf( "Cannot locate data file - %s\n", filename ); beep(); sleep( 5 ); return; } /* * create an error file for this leg data * duplicate times will stored here */ err_filename = tprintf( "%s%d.err" , manstart ? "Sleg" : "leg" , leg ); efile = fopen( err_filename, "at" ); /* * Process each entry in the file */ if( leg > config.num_legs ) printf( "\nUploading leg%d start information\n", leg ); while( fgets( line, 101, ufile ) ) { if( sscanf( line, "%d %d:%d:%d", &team, &hh, &mm, &ss ) != 4 ) { printf( "Upload error - %s", line ); error++; } else { if( !ins_data( team, hh, mm, ss ) ) error++; ntms++; } } printf( "%d errors detected. %d teams uploaded. Any key to continue ", error, ntms ); getinp(); fclose( ufile ); fclose( efile ); } /*======================================================================== * * Insert time info into data base * * Purpose: * This helper function is called to Insert time info into data base * Read record * Read and convert time * Write record * Maintain error file * Display errors on screen * * Parameters: * tm Team * hh hours * mm minutes * ss seconds * * Returns: * Nothing * *========================================================================*/ int ins_data( int tm, int hh, int mm, int ss ) { time_t l_time; /* Leg time */ int ok = TRUE; /* * Calculate the time for the team */ l_time = conv_time( hh, mm, ss ); /* * If an error is found - invalid team, team not found or dual time for team * a message is output to the screen and the data is written to error file * FALSE is returned */ if( !valid_field( tm ) ) { printf( "Invalid team - %d %2.2d:%2.2d:%2.2d\n", tm, hh, mm, ss ); fprintf( efile, "Invalid team - %d %2.2d:%2.2d:%2.2d\n", tm, hh, mm, ss ); ok = FALSE; return ( ok ); } if( !g_record( tm, &team_buf ) ) { printf( "Team not found -% d %2.2d:%2.2d:%2.2d\n", tm, hh, mm, ss ); fprintf( efile, "Team not found - %d %2.2d:%2.2d:%2.2d\n", tm, hh, mm, ss ); ok = FALSE; } if( !manstart ) { /* Normal upload */ if( team_buf.leg[leg].end > 0 && team_buf.leg[leg].end != l_time ) { printf( "Dual time for %d - %2.2d:%2.2d:%2.2d and %s\n", tm, hh, mm, ss, time_a( team_buf.leg[leg].end ) ); fprintf( efile, "Dual time for %d - %2.2d:%2.2d:%2.2d and %s\n", tm, hh, mm, ss, time_a( team_buf.leg[leg].end ) ); /* write duplicate time to error file */ ok = FALSE; return ( ok ); /* keep time already in database */ } team_buf.leg[leg].end = l_time; } else { /* Uplaod start time */ team_buf.leg[leg].start = l_time; team_buf.leg[leg].manual = TRUE; } set_times( &team_buf ); /* Calc start of next leg */ ( void ) test_times( &team_buf, 0 ); /* Calc elapsed times etc */ put_team_record( tm, &team_buf ); return ( ok ); } /*======================================================================== * * Extended upload functions menu * * Purpose: * This function is called to Extended upload functions * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void supload(void) { do_menu( "Extended data manipulation", "Select option", sup_menu ); /* Call a menu to do it */ } /*======================================================================== * * Read in text team information * * Purpose: * This function is called to do Read in text team information * from a file * * The source file is a comma seperated file and may contain the * folowing items * * Team Number - Mandatory * Team Name - Mandatory * Team Catagory - Mandatory * * Team Names ... - Optional * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tupload(void) { int error = 0; int i; char *linep; int class_count[MAX_CLASS]; int total; cur( 0, 5 ); printf( "Read text file of team information" ); if( !getfname( "Enter name of the file to read :", ".csv" ) ) return; printf( "\n" ); ufile = fopen( ufilename, "rt" ); /* Open the file for reading */ if( ufile == 0 ) { printf( "Cannot locate data file - %s\n", ufilename ); beep(); sleep( 5 ); return; } memset ( class_count, 0, sizeof( class_count )); /* ** Get the data from the file ** Read in lines one by one */ while( fgets( line, sizeof(line) - 10 , ufile ) ) { linep = line; /* ** Skip blank lines ** Skip leading white space */ for ( linep = line; isspace( *linep ); linep++ ) { } if ( ! *linep ) continue; /* ** The first entry on the line should be team number ** If it is not a valid team number then skip */ if( ! t_parse_number( &linep, &team ) ) { printf( "No team number: %-30s.\n", line ); error++; } else if( ! valid_field( team ) ) { printf ( "Invalid team number: %d\n", team ); error++; } else { g_record( team, &team_buf ); /* ** Extract a team information from the CSV file ** These fields will be ** - Team Name ** - Category ** - Member names */ if ( t_parse_text( &linep, line_text ) ) { strncpy (team_buf.name,line_text,MAX_TM_NAME); } if ( t_parse_text( &linep, line_text ) ) { int cat_found = 0; team_buf.class = lookup_class( line_text, NULL ); if ( team_buf.class > 0) { /* ** The team has a category ** Now flag the team as valid - it has ALL ** the basic information */ team_buf.flags.valid = TRUE; cat_found =1; if ( team_buf.class < MAX_CLASS ) class_count[team_buf.class]++; } if ( !cat_found && *line_text ) { printf( "Team: %d - Invalid category:%s\n", team,line_text ); error++; } } for( i = 0; i < MAX_MEMB; i++ ) { if ( t_parse_text( &linep, line_text ) ) { strncpy (team_buf.members[i].name,line_text,MAX_PERSON_NAME); } } put_team_record( team, &team_buf ); } /* ** printf( ">>>:%s\n", line ); ** if ( 'q' == getinp() ) break; */ } /* ** Display a few upload stats */ total = 0; for( i = 0; i < config.num_class; i++ ) { printf( "%*s : %d\n", LEN_CLASS_NAME, config.team_class[i].full_name, class_count[i+1] ); total += class_count[i+1]; } printf( "\n%*s : %d\n", LEN_CLASS_NAME, "Total Uploaded", total ); printf( "%*s : %d\n", LEN_CLASS_NAME, "Errors", error ); printf( "\nAny key to continue " ); getinp(); fclose( ufile ); } /*======================================================================== * * Parse a number from a CSV text file * * Purpose: * This helper function is called to Parse line of team text * * Parameters: * linep Current input source pointer * Will be updated to point to end of the field * number Number extracted * * Returns: * TRUE - Number extracted OK * FALSE - No number extracted * *========================================================================*/ bool t_parse_number( char **linep, int *number ) { long lnumber; /* ** Expecting a number ** strtol will remove leading white space */ lnumber = strtol( *linep, linep, 10 ); /* ** Skip the trailing delimiter(s) */ while ( p_del(*linep) ) { (*linep)++; } /* ** A valid number ? */ if ( lnumber == 0 ) return FALSE; *number = (int) lnumber; return TRUE; } /*======================================================================== * * Parse a text field from a CSV text file * * Purpose: * This helper function is called to Parse line of team text * * Parameters: * linep Current input source pointer * Will be updated to point to end of the field * number Address of buffer to insert text into * * Returns: * TRUE - Field extracted OK * FALSE - No field extracted * *========================================================================*/ bool t_parse_text( char **linep, char *text ) { char uch; char *textp = text; bool quoted = FALSE; /* ** If we have already reached the end of the line tne indicate ** That there is no data */ uch = **linep; if ( uch == '\n' || uch == '\r' || uch == '\0' ) return ( FALSE ); /* ** Extract the next record */ while ( TRUE ) { uch = **linep; /* ** End of the field */ if ( uch == '\n' || uch == '\r' || uch == '\0' ) break; (*linep)++; if ( !quoted && uch == ',' ) { break; } /* ** An unquoted " will start scanning for a matching quote */ if ( !quoted && uch == '"' ) { quoted = TRUE; continue; } /* ** A quoted " may be en embedded quote or the end of a quote */ if ( quoted && uch == '"' ) { if ( **linep != '"' ) { quoted = FALSE; continue; } /* ** Skip one " and pick up the next */ (*linep)++; } /* ** Save this character */ *textp++ = uch; } /* ** Clean up the extracted string */ *textp = 0; compact ( text ); return ( TRUE ); } /*======================================================================== * * Test for a delimiter. * * Purpose: * This function is called to Test for a delimiter. * * Parameters: * c Character to test * * Returns: * TRUE if a delimter (space, tab or comma) * *========================================================================*/ char p_del( char *c ) { return ( *c == ' ' || *c == '\t' || *c == ',' || *c == '\0' || *c == '\n' || *c == '\r'); } char p_eol( char *c ) { return ( *c == '\0' || *c == '\n' || *c == '\r' ); } /*======================================================================== * * Generate team name file * * Purpose: * This function is called to Generate team name file * * The file contains team number,Team name,Team class * The operator is prompted to enter the name of the file * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tdnload(void) { int i; cur( 0, 5 ); printf( "Create text file of team information" ); if( !getfname( "Enter name of the file to create :", ".txt" ) ) return; printf( "\n" ); ufile = fopen( ufilename, "wt" ); /* Open the file for writing */ if( ufile == 0 ) { printf( "Cannot create data file - %s\n", ufilename ); beep(); sleep( 5 ); return; } /* * Put the data into the file */ for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { fprintf( ufile, "%-5d,%-30s,%-5s\n", team_buf.numb, team_buf.name, team_buf.class > 0 ? config.team_class[team_buf.class - 1].abr : "" ); } } fclose( ufile ); } /*======================================================================== * * Generate leg timing file * * Purpose: * This function is called to Generate leg timing file * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void dnload(void) { int i; char stend[] = "E"; cur( 0, 5 ); printf( "Generate leg data files" ); while( TRUE ) { leg = 0; d_field( 0, 6, "Enter leg to save :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - exit loop */ break; beep(); /* Make a noise and keep waiting for valid number */ } /* * Find out if Start or End of leg times to be saved */ do { d_field( 0, 7, "Start of End of leg to save :", D_USTRING, 1, stend, TRUE, M_UPDATE ); } while( ( stend[0] != 'S' ) && ( stend[0] != 'E' ) ); manstart = ( stend[0] == 'S' ? TRUE : FALSE ); /* * Locate the required data file and prepare for processing */ printf( "\n" ); sprintf( ufilename, ( manstart ? "Sleg%d" : "leg%d" ), leg ); /* Create the file name */ ufile = fopen( ufilename, "wt" ); /* Open the file for writing */ if( ufile == 0 ) { printf( "Cannot create data file - %s\n", ufilename ); beep(); sleep( 5 ); return; } /* * Write the data to the data file */ for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { if( !manstart && ( leg <= config.num_legs && team_buf.leg[leg].end >= 0 ) ) fprintf( ufile, "%d %s\n", i, time_a( team_buf.leg[leg].end ) ); if( manstart && team_buf.leg[leg].start >= 0 ) fprintf( ufile, "%d %s\n", i, time_a( team_buf.leg[leg].start ) ); } } fclose( ufile ); } /*======================================================================== * * Get a filename from the user * * Purpose: * This function is called to Get a filename from the user * * Parameters: * prompt User prompt * ext File extension * * Returns: * TRUE: all is well * *========================================================================*/ char getfname( char *prompt, char *ext ) { /* ** Create a default name if non is present */ if ( ! *ufilename ) { sprintf( ufilename, "%s%s", filebase, ext ); } d_field( 0, 6, prompt, D_STRING, 40, ufilename, TRUE, M_UPDATE ); if( abort_flag ) return ( FALSE ); compact( ufilename ); if( ufilename[0] ) return ( TRUE ); return ( FALSE ); } /********************************* EOF ***********************************/