Rev 54 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/************************************************************************** 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 <stdio.h>#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', "Store team information from external file", tdnload_store },{ '3', "Create external team information file", tdnload },{ '4', "Create external leg data file", dnload },{ '5', "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;int has_data = 0;/*** Skip blank lines** Skip leading white space*/for ( linep = line; *linep; linep++ ){if ( *linep == (char)0xA0 || *linep == '"' || *linep == ',' || *linep == '\n' ||*linep == '\r'){continue;}has_data = 1;}if ( !has_data )continue;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 ( ! *line_text ){printf( "Team: %d - No Team Name:%50.50s...\n", team, line );}}if ( t_parse_text( &linep, line_text ) && *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 ){printf( "Team: %d - Invalid category:%s\n", team,line_text );error++;}}else{printf( "Team: %d - No category:%50.50s...\n", team, line );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);}int age;if ( t_parse_number( &linep, &age ) ){team_buf.members[i].age = age;}}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* If the field is a valid number* number Number extracted** Returns:* TRUE - Number extracted OK* FALSE - No number extracted**========================================================================*/bool t_parse_number( char **linep, int *number ){long lnumber;char *work = *linep;char *endp;/*** Extract data from the CSV field** May need to remove quotes** Use temp work space*/t_parse_text( &work, line_text);/*** Expecting a number** strtol will remove leading white space*/lnumber = strtol( line_text, &endp, 10 );/*** A valid number ?** All the field must be numeric, otherwise it wasn't a number*/if ( lnumber == 0 || *endp )return FALSE;*number = (int) lnumber;*linep = work;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)++;/*** Ugly character from MS CSV files*/if ( uch == (char) 0xA0 ){continue;}if ( !quoted && uch == ',' ){break;}/*** An unquoted " will start scanning for a matching quote*/if ( !quoted && uch == '"' ){quoted = TRUE;continue;}/*** A quoted " may be an 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 in the format* that can be read by the load command** 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_store(void){int i;int j;cur( 0, 5 );printf( "Create text file of team information" );if( !getfname( "Enter name of the file to create :", ".csv.txt" ) )return;printf( "\n" );/*** Open printer, with known filename*/if( !open_printer_name( ufilename, 2000, FALSE, NULL ) ){beep();sleep( 5 );return;}/*** Print headings*/csv_print( "%s", "Team Number" );csv_print( "%s", "Team Name" );csv_print( "%s", "Class Abr");for( j = 1; j <= config.num_legs; j++ ){csv_print( "%s", "Competitor Name");csv_print( "%s", "Age");}csv_print("\n");/** 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 ) ){/*** Basic information** - Team number** - Full team name*/csv_print( "%d", team_buf.numb );csv_print( "%s", team_buf.name );csv_print( "%s", team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].abr );for( j = 1; j <= config.num_legs; j++ ){csv_print( "%s", team_buf.members[j-1].name );csv_print( "%d", team_buf.members[j-1].age );}csv_print( "\n" );}}close_printer();}/*========================================================================** 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 ***********************************/