/******************************************************************************/ /* */ /* TA_Bench read_yahoo.c 03/07/2013 */ /* */ /******************************************************************************/ /***************************************************************************** * * This example source code introduces a c library buffered I/O interface to * URL reads it supports fopen(), fread(), fgets(), feof(), fclose(), * rewind(). Supported functions have identical prototypes to their normal c * lib namesakes and are preceaded by url_ . * * Using this code you can replace your program's fopen() with url_fopen() * and fread() with url_fread() and it become possible to read remote streams * instead of (only) local files. Local files (ie those that can be directly * fopened) will drop back to using the underlying clib implementations * * See the main() function at the bottom that shows an app that retrives from a * specified url using fgets() and fread() and saves as two output files. * * This example requires libcurl 7.9.7 or later. */ #include #include #ifndef WIN32 # include #endif #include #include #include /******************************************************************************/ /* */ /* Structures And Declarations. */ /* */ /******************************************************************************/ enum fcurl_type_e { CFTYPE_NONE=0, CFTYPE_FILE=1, CFTYPE_CURL=2 }; struct fcurl_data { enum fcurl_type_e type; /* type of handle */ union { CURL *curl; FILE *file; } handle; /* handle */ char *buffer; /* buffer to store cached data*/ size_t buffer_len; /* currently allocated buffers length */ size_t buffer_pos; /* end of data in buffer*/ int still_running; /* Is background url fetch still in progress */ }; typedef struct fcurl_data URL_FILE; /* Exported Functions */ URL_FILE *url_fopen(const char *url,const char *operation); int url_fclose(URL_FILE *file); int url_feof(URL_FILE *file); size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file); char * url_fgets(char *ptr, size_t size, URL_FILE *file); void url_rewind(URL_FILE *file); /* we use a global one for convenience */ CURLM *multi_handle; // url="http://192.168.7.3/testfile";/* default to testurl */ // url="DineenConsulting.com";/* default to testurl */ // url="http://finance.yahoo.com/q/hp?s=SPY+Historical+Prices"; /* default to testurl */ /******************************************************************************/ /* */ /* Function: Read_Yahoo_Primary */ /* */ /******************************************************************************/ int Read_Yahoo_Primary ( Stock_Data_Struct *Stock_Data_Head, Stock_Div_Struct *Stock_Div_Head, Stock_Data_Info_Struct *Stock_Info_Head, Date_Struct Date_Start, Date_Struct Date_End, char Symbol[10], char Type, Print_Struct *Print_Head ) { URL_FILE *handle; FILE *outf; FILE *Test_Handle; int nread; char buffer[256]; // Was 256 char Char_Temp[16]; const char *url; char URL_String[256]; char Temp[256]; int year; int month; int day; float open_read; float high_read; float low_read; float close_read; long long int volume_read; float adj_close_read; float open; float high; float low; float close; long long int volume; float adj_close; float dividend; Stock_Data_Struct *curr_ptr; Stock_Data_Struct *new_ptr; Stock_Data_Struct *prev_ptr; Stock_Div_Struct *div_curr_ptr; Stock_Div_Struct *div_new_ptr; Stock_Div_Struct *div_prev_ptr; int First_Record; int Entry_Count; float Price_High; float Price_Low; float Split_Divisor; float Divisor; float Int_Divisor; /******************************************************************************/ /* */ /* Print The Input Variables: */ /* */ /******************************************************************************/ if ( Print_Head->Print_Headers_Read == TRUE ) { printf ( "Running Read_Yahoo\n") ; printf ( "Start Date: Month = %d\n", Date_Start.Month ); printf ( "Start Date: Day = %d\n", Date_Start.Day ); printf ( "Start Date: Year = %d\n", Date_Start.Year ); printf ( "End Date: Month = %d\n", Date_End.Month ); printf ( "End Date: Day = %d\n", Date_End.Day ); printf ( "End Date: Year = %d\n", Date_End.Year ); printf ( "Symbol = %s\n", Symbol ); printf ( "Type = %c\n", Type ); } /******************************************************************************/ /* */ /* Assemble The URL: */ /* */ /******************************************************************************/ strcpy ( URL_String, "http://ichart.finance.yahoo.com/table.csv?s=" ); strcat ( URL_String, Symbol ); strcat ( URL_String, "&a=" ); sprintf ( Temp, "%d", Date_Start.Month-1); strcat ( URL_String, Temp ); strcat ( URL_String, "&b=" ); sprintf ( Temp, "%d", Date_Start.Day ); strcat ( URL_String, Temp ); strcat ( URL_String, "&c=" ); sprintf ( Temp, "%d", Date_Start.Year); strcat ( URL_String, Temp ); strcat ( URL_String, "&g=" ); sprintf ( Temp, "%c", Type ); strcat ( URL_String, Temp ); strcat ( URL_String, "&d=" ); sprintf ( Temp, "%d", Date_End.Month-1); strcat ( URL_String, Temp ); strcat ( URL_String, "&e=" ); sprintf ( Temp, "%d", Date_End.Day); strcat ( URL_String, Temp ); strcat ( URL_String, "&f=" ); sprintf ( Temp, "%d", Date_End.Year); strcat ( URL_String, Temp ); strcat ( URL_String, "&ignore=.csv" ); if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "URL String = %s\n", URL_String ); /* url="http://ichart.finance.yahoo.com/table.csv?s=SPY&d=10&e=2&f=2012&g=d&a=0&b=29&c=1993&ignore=.csv"; */ /* url="http://ichart.finance.yahoo.com/table.csv?s=SPY&d=10&e=2&f=2012&g=d&a=0&b=29&c=1993&ignore=.csv"; */ /******************************************************************************/ /* */ /* Read The Data From The Yahoo Web Site: */ /* */ /******************************************************************************/ if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Start The Yahoo Web Site Read\n" ); handle = url_fopen ( URL_String, "r" ); if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Handle = %d\n", handle ); if( !handle ) { printf( "Couldn't Open URL: url_fopen() %s\n", url ); printf ( "Handle = %d\n", handle ); fclose( outf ); return -1; } /******************************************************************************/ /* */ /* Read The Price / Volume Data: */ /* */ /******************************************************************************/ if ( Type == 'd' || Type == 'w' || Type == 'm' ) { /* Start Type Price Data Block */ if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Start The Price Volume Read\n" ); curr_ptr = Stock_Data_Head; prev_ptr = Stock_Data_Head; prev_ptr->high = 1000000.0; First_Record = TRUE; Entry_Count = 0; Price_High = 0.0; Price_Low = 1000000000.0; Split_Divisor = 1.0; Divisor = 0.0; Int_Divisor = 1.0; while( !url_feof( handle )) { /* Start While */ url_fgets( buffer, sizeof( buffer ), handle); if ( strstr ( buffer, "404 Not Found" ) != NULL ) { printf( "Error 404 Symbol Not Found\n" ); fclose( outf ); return ( -1 ); } if ( Print_Head->Print_Data == TRUE ) printf ( "%s", buffer ); if ( First_Record == FALSE ) { /* Start Not First_Record */ sscanf ( buffer, "%4d", &year ); sscanf ( buffer+5, "%2d", &month ); sscanf ( buffer+8, "%2d", &day ); sscanf ( buffer+11, "%f,%f,%f,%f,%lli,%f", &open_read, &high_read, &low_read, &close_read, &volume_read, &adj_close_read ); if ( ( 1.40 * Split_Divisor * prev_ptr->high ) <= high_read ) { /* Start Block Split Occured */ Divisor = ( high_read / (Split_Divisor*prev_ptr->high)); if ( Divisor >= 7.8 ) Int_Divisor = 8; else if ( Divisor >= 6.8 ) Int_Divisor = 7; else if ( Divisor >= 5.8 ) Int_Divisor = 6; else if ( Divisor >= 4.8 ) Int_Divisor = 5; else if ( Divisor >= 3.8 ) Int_Divisor = 4; else if ( Divisor >= 2.8 ) Int_Divisor = 3; else if ( Divisor >= 1.6 ) Int_Divisor = 2; else if ( Divisor >= 1.3 ) Int_Divisor = 1.5; Split_Divisor = (float) Split_Divisor * Int_Divisor; curr_ptr->Split_Occured = TRUE; if ( Print_Head->Print_Data == TRUE ) printf ( "Split Detected: Date: %d/%d/%d Int_Divisor %d Split_Divisor %f\n", month, day, year, Int_Divisor, Split_Divisor); } /* End Block Split Occured */ else { /* Start Block No Split Occured */ Int_Divisor = 0.0; curr_ptr->Split_Occured = FALSE; }; /* End Block No Split Occured */ open = open_read / Split_Divisor; high = high_read / Split_Divisor; low = low_read / Split_Divisor; close = close_read / Split_Divisor; volume = volume_read; adj_close = adj_close_read / Split_Divisor; if ( Print_Head->Print_Data == TRUE ) { printf ( "Curr_Ptr %x\n", curr_ptr ); printf ( "Date: %4i %2i %2i\n", year, month, day ); printf ( "Open: %2.2f\n", open); printf ( "High: %2.2f\n", high ); printf ( "Low: %2.2f\n", low ); printf ( "Close: %2.2f\n", close ); printf ( "Volume: %i\n", volume ); printf ( "Adj_Close: %2.2f\n", adj_close ); printf ( "High_Read: %2.2f\n", high_read); printf ( "Prev High: %2.2f\n", prev_ptr->high ); printf ( "Divisor: %2.2f\n", Divisor ); printf ( "Split_Divisor: %2.2f\n", Split_Divisor ); printf ( "Int_Divisor: %2.2f\n\n", Int_Divisor ); }; curr_ptr->year = year; curr_ptr->month = month; curr_ptr->day = day; curr_ptr->open = open; curr_ptr->high = high; curr_ptr->low = low; curr_ptr->close = close; curr_ptr->volume = volume; curr_ptr->adj_close = adj_close; curr_ptr->open_read = open_read; curr_ptr->high_read = high_read; curr_ptr->low_read = low_read; curr_ptr->close_read = close_read; curr_ptr->volume_read = volume_read; curr_ptr->adj_close_read = adj_close_read; curr_ptr->Int_Divisor = Int_Divisor; curr_ptr->Split_Divisor = Split_Divisor; curr_ptr->Entry_Count = Entry_Count; if ( high > Price_High ) Price_High = high; if ( low < Price_Low ) Price_Low = low; if ( Print_Head->Print_Data == TRUE ) { printf ( "Price_High = %f\n", Price_High ); printf ( "Price_Low = %f\n", Price_Low ); }; new_ptr = malloc( sizeof( Stock_Data_Struct) ); curr_ptr->next_ptr = new_ptr; curr_ptr->prev_ptr = prev_ptr; prev_ptr = curr_ptr; curr_ptr = new_ptr; Entry_Count++; }; /* End Not First_Record */ First_Record = FALSE; }; /* End While */ if ( Entry_Count != NULL ) curr_ptr = prev_ptr; curr_ptr->next_ptr = NULL; Stock_Info_Head->Date_Start.Day = Date_Start.Day; Stock_Info_Head->Date_Start.Month = Date_Start.Month; Stock_Info_Head->Date_Start.Year= Date_Start.Year; Stock_Info_Head->Date_End.Day = Date_End.Day; Stock_Info_Head->Date_End.Month = Date_End.Month; Stock_Info_Head->Date_End.Year = Date_End.Year; strcpy ( Stock_Info_Head->Symbol, Symbol ); Stock_Info_Head->Type = Type; Stock_Info_Head->Entry_Count = Entry_Count; Stock_Info_Head->Price_High = Price_High; Stock_Info_Head->Price_Low = Price_Low; Stock_Info_Head->First_Ptr = Stock_Data_Head; Stock_Info_Head->Last_Ptr = curr_ptr; url_fclose(handle); return (NULL); /* all done */ } /* End Type Price Data Block */ else /******************************************************************************/ /* */ /* Read The Dividend Data: */ /* */ /******************************************************************************/ if ( Type == 'v' ) { /* Start Type Dividend Data Block */ if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Start The Dividend Read\n" ); div_curr_ptr = Stock_Div_Head; div_prev_ptr = NULL; First_Record = TRUE; Entry_Count = 0; while( !url_feof( handle )) { /* Start While */ url_fgets( buffer, sizeof( buffer ), handle); if ( Print_Head->Print_Data == TRUE ) printf ( "%s", buffer ); if ( First_Record == FALSE ) { /* Start Not First_Record */ sscanf ( buffer, "%4d", &year ); sscanf ( buffer+5, "%2d", &month ); sscanf ( buffer+8, "%2d", &day ); sscanf ( buffer+11, "%f", ÷nd ); if ( Print_Head->Print_Data == TRUE ) { printf ( "Curr_Ptr %x\n", div_curr_ptr ); printf ( "Date: %4i %2i %2i\n", year, month, day ); printf ( "Dividend %2.2f\n", dividend ); }; div_curr_ptr->year = year; div_curr_ptr->month = month; div_curr_ptr->day = day; div_curr_ptr->Dividend = dividend; div_new_ptr = malloc( sizeof( Stock_Div_Struct) ); div_curr_ptr->next_ptr = div_new_ptr; div_curr_ptr->prev_ptr = div_prev_ptr; div_prev_ptr = div_curr_ptr; div_curr_ptr = div_new_ptr; Entry_Count++; }; /* End Not First_Record */ First_Record = FALSE; }; /* End While */ if ( Entry_Count != 0 ) div_curr_ptr = div_prev_ptr; div_curr_ptr->next_ptr = NULL; Stock_Info_Head->Date_Start.Day = Date_Start.Day; Stock_Info_Head->Date_Start.Month = Date_Start.Month; Stock_Info_Head->Date_Start.Year= Date_Start.Year; Stock_Info_Head->Date_End.Day = Date_End.Day; Stock_Info_Head->Date_End.Month = Date_End.Month; Stock_Info_Head->Date_End.Year = Date_End.Year; strcpy ( Stock_Info_Head->Symbol, Symbol ); Stock_Info_Head->Type = Type; Stock_Info_Head->Entry_Count = Entry_Count; Stock_Info_Head->First_Ptr = Stock_Div_Head; Stock_Info_Head->Last_Ptr = div_curr_ptr; url_fclose(handle); return (NULL); /* all done */ } /* End Type Dividend Data Block */ }; /******************************************************************************/ /* */ /* Function: Read_Yahoo_Secondary */ /* */ /******************************************************************************/ int Read_Yahoo_Secondary ( Stock_Data_Struct *Stock_Data_Head, Stock_Div_Struct *Stock_Div_Head, Stock_Data_Info_Struct *Stock_Info_Head, Date_Struct Date_Start, Date_Struct Date_End, char Symbol[10], char Type, Print_Struct *Print_Head ) { URL_FILE *handle; FILE *outf; FILE *Test_Handle; int nread; char buffer[256]; // Was 256 char Char_Temp[16]; const char *url; char URL_String[256]; char Temp[256]; int year; int month; int day; float open_read; float high_read; float low_read; float close_read; long long int volume_read; float adj_close_read; float open; float high; float low; float close; long long int volume; float adj_close; float dividend; Stock_Data_Struct *curr_ptr; Stock_Data_Struct *new_ptr; Stock_Data_Struct *prev_ptr; Stock_Div_Struct *div_curr_ptr; Stock_Div_Struct *div_new_ptr; Stock_Div_Struct *div_prev_ptr; int First_Record; int Entry_Count; float Price_High; float Price_Low; float Split_Divisor; float Divisor; float Int_Divisor; /******************************************************************************/ /* */ /* Print The Input Variables: */ /* */ /******************************************************************************/ if ( Print_Head->Print_Headers_Read == TRUE ) { printf ( "Running Read_Yahoo\n") ; printf ( "Start Date: Month = %d\n", Date_Start.Month ); printf ( "Start Date: Day = %d\n", Date_Start.Day ); printf ( "Start Date: Year = %d\n", Date_Start.Year ); printf ( "End Date: Month = %d\n", Date_End.Month ); printf ( "End Date: Day = %d\n", Date_End.Day ); printf ( "End Date: Year = %d\n", Date_End.Year ); printf ( "Symbol = %s\n", Symbol ); printf ( "Type = %c\n", Type ); } /******************************************************************************/ /* */ /* Assemble The URL: */ /* */ /******************************************************************************/ strcpy ( URL_String, "http://ichart.finance.yahoo.com/table.csv?s=" ); strcat ( URL_String, Symbol ); strcat ( URL_String, "&a=" ); sprintf ( Temp, "%d", Date_Start.Month-1); strcat ( URL_String, Temp ); strcat ( URL_String, "&b=" ); sprintf ( Temp, "%d", Date_Start.Day ); strcat ( URL_String, Temp ); strcat ( URL_String, "&c=" ); sprintf ( Temp, "%d", Date_Start.Year); strcat ( URL_String, Temp ); strcat ( URL_String, "&g=" ); sprintf ( Temp, "%c", Type ); strcat ( URL_String, Temp ); strcat ( URL_String, "&d=" ); sprintf ( Temp, "%d", Date_End.Month-1); strcat ( URL_String, Temp ); strcat ( URL_String, "&e=" ); sprintf ( Temp, "%d", Date_End.Day); strcat ( URL_String, Temp ); strcat ( URL_String, "&f=" ); sprintf ( Temp, "%d", Date_End.Year); strcat ( URL_String, Temp ); strcat ( URL_String, "&ignore=.csv" ); if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "URL String = %s\n", URL_String ); /* url="http://ichart.finance.yahoo.com/table.csv?s=SPY&d=10&e=2&f=2012&g=d&a=0&b=29&c=1993&ignore=.csv"; */ /* url="http://ichart.finance.yahoo.com/table.csv?s=SPY&d=10&e=2&f=2012&g=d&a=0&b=29&c=1993&ignore=.csv"; */ /******************************************************************************/ /* */ /* Read The Data From The Yahoo Web Site: */ /* */ /******************************************************************************/ if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Start The Yahoo Web Site Read\n" ); handle = url_fopen ( URL_String, "r" ); if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Handle = %d\n", handle ); if( !handle ) { printf( "Couldn't Open URL: url_fopen() %s\n", url ); printf ( "Handle = %d\n", handle ); fclose( outf ); return -1; } /******************************************************************************/ /* */ /* Read The Price / Volume Data: */ /* */ /******************************************************************************/ if ( Type == 'd' || Type == 'w' || Type == 'm' ) { /* Start Type Price Data Block */ if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Start The Price Volume Read\n" ); curr_ptr = Stock_Data_Head; prev_ptr = Stock_Data_Head; prev_ptr->high = 1000000.0; First_Record = TRUE; Entry_Count = 0; Price_High = 0.0; Price_Low = 1000000000.0; Split_Divisor = 1.0; Divisor = 0.0; Int_Divisor = 0.0; while( !url_feof( handle )) { /* Start While */ url_fgets( buffer, sizeof( buffer ), handle); if ( strstr ( buffer, "404 Not Found" ) != NULL ) { printf( "Error 404 Symbol Not Found\n" ); fclose( outf ); return ( -1 ); } if ( Print_Head->Print_Data == TRUE ) printf ( "%s", buffer ); if ( First_Record == FALSE ) { /* Start Not First_Record */ sscanf ( buffer, "%4d", &year ); sscanf ( buffer+5, "%2d", &month ); sscanf ( buffer+8, "%2d", &day ); sscanf ( buffer+11, "%f,%f,%f,%f,%lli,%f", &open_read, &high_read, &low_read, &close_read, &volume_read, &adj_close_read ); if ( ( 1.40 * Split_Divisor * prev_ptr->high ) <= high_read ) { /* Start Block Split Occured */ Divisor = ( high_read / (Split_Divisor*prev_ptr->high)); if ( Divisor >= 7.8 ) Int_Divisor = 8; else if ( Divisor >= 6.8 ) Int_Divisor = 7; else if ( Divisor >= 5.8 ) Int_Divisor = 6; else if ( Divisor >= 4.8 ) Int_Divisor = 5; else if ( Divisor >= 3.8 ) Int_Divisor = 4; else if ( Divisor >= 2.8 ) Int_Divisor = 3; else if ( Divisor >= 1.6 ) Int_Divisor = 2; else if ( Divisor >= 1.3 ) Int_Divisor = 1.5; Split_Divisor = (float) Split_Divisor * Int_Divisor; curr_ptr->Split_Occured = TRUE; if ( Print_Head->Print_Data == TRUE ) printf ( "Split Detected: Date: %d/%d/%d Int_Divisor %d Split_Divisor %f\n", month, day, year, Int_Divisor, Split_Divisor); } /* End Block Split Occured */ else { /* Start Block No Split Occured */ Int_Divisor = 0.0; curr_ptr->Split_Occured = FALSE; }; /* End Block No Split Occured */ open = open_read / Split_Divisor; high = high_read / Split_Divisor; low = low_read / Split_Divisor; close = close_read / Split_Divisor; volume = volume_read; adj_close = adj_close_read / Split_Divisor; if ( Print_Head->Print_Data == TRUE ) { printf ( "Curr_Ptr %x\n", curr_ptr ); printf ( "Date: %4i %2i %2i\n", year, month, day ); printf ( "Open: %2.2f\n", open); printf ( "High: %2.2f\n", high ); printf ( "Low: %2.2f\n", low ); printf ( "Close: %2.2f\n", close ); printf ( "Volume: %i\n", volume ); printf ( "Adj_Close: %2.2f\n", adj_close ); printf ( "High_Read: %2.2f\n", high_read); printf ( "Prev High: %2.2f\n", prev_ptr->high ); printf ( "Divisor: %2.2f\n", Divisor ); printf ( "Split_Divisor: %2.2f\n", Split_Divisor ); printf ( "Int_Divisor: %2.2f\n\n", Int_Divisor ); }; curr_ptr->year = year; curr_ptr->month = month; curr_ptr->day = day; curr_ptr->open = open; curr_ptr->high = high; curr_ptr->low = low; curr_ptr->close = close; curr_ptr->volume = volume; curr_ptr->adj_close = adj_close; curr_ptr->open_read = open_read; curr_ptr->high_read = high_read; curr_ptr->low_read = low_read; curr_ptr->close_read = close_read; curr_ptr->volume_read = volume_read; curr_ptr->adj_close_read = adj_close_read; curr_ptr->Int_Divisor = Int_Divisor; curr_ptr->Split_Divisor = Split_Divisor; curr_ptr->Entry_Count = Entry_Count; if ( high > Price_High ) Price_High = high; if ( low < Price_Low ) Price_Low = low; if ( Print_Head->Print_Data == TRUE ) { printf ( "Price_High = %f\n", Price_High ); printf ( "Price_Low = %f\n", Price_Low ); }; new_ptr = malloc( sizeof( Stock_Data_Struct) ); curr_ptr->next_ptr = new_ptr; curr_ptr->prev_ptr = prev_ptr; prev_ptr = curr_ptr; curr_ptr = new_ptr; Entry_Count++; }; /* End Not First_Record */ First_Record = FALSE; }; /* End While */ if ( Entry_Count != NULL ) curr_ptr = prev_ptr; curr_ptr->next_ptr = NULL; Stock_Info_Head->Date_Start.Day = Date_Start.Day; Stock_Info_Head->Date_Start.Month = Date_Start.Month; Stock_Info_Head->Date_Start.Year= Date_Start.Year; Stock_Info_Head->Date_End.Day = Date_End.Day; Stock_Info_Head->Date_End.Month = Date_End.Month; Stock_Info_Head->Date_End.Year = Date_End.Year; strcpy ( Stock_Info_Head->Symbol, Symbol ); Stock_Info_Head->Type = Type; Stock_Info_Head->Entry_Count = Entry_Count; Stock_Info_Head->Price_High = Price_High; Stock_Info_Head->Price_Low = Price_Low; Stock_Info_Head->First_Ptr = Stock_Data_Head; Stock_Info_Head->Last_Ptr = curr_ptr; url_fclose(handle); return (NULL); /* all done */ } /* End Type Price Data Block */ else /******************************************************************************/ /* */ /* Read The Dividend Data: */ /* */ /******************************************************************************/ if ( Type == 'v' ) { /* Start Type Dividend Data Block */ if ( Print_Head->Print_Headers_Read == TRUE ) printf ( "Start The Dividend Read\n" ); div_curr_ptr = Stock_Div_Head; div_prev_ptr = NULL; First_Record = TRUE; Entry_Count = 0; while( !url_feof( handle )) { /* Start While */ url_fgets( buffer, sizeof( buffer ), handle); if ( Print_Head->Print_Data == TRUE ) printf ( "%s", buffer ); if ( First_Record == FALSE ) { /* Start Not First_Record */ sscanf ( buffer, "%4d", &year ); sscanf ( buffer+5, "%2d", &month ); sscanf ( buffer+8, "%2d", &day ); sscanf ( buffer+11, "%f", ÷nd ); if ( Print_Head->Print_Data == TRUE ) { printf ( "Curr_Ptr %x\n", div_curr_ptr ); printf ( "Date: %4i %2i %2i\n", year, month, day ); printf ( "Dividend %2.2f\n", dividend ); }; div_curr_ptr->year = year; div_curr_ptr->month = month; div_curr_ptr->day = day; div_curr_ptr->Dividend = dividend; div_new_ptr = malloc( sizeof( Stock_Div_Struct) ); div_curr_ptr->next_ptr = div_new_ptr; div_curr_ptr->prev_ptr = div_prev_ptr; div_prev_ptr = div_curr_ptr; div_curr_ptr = div_new_ptr; Entry_Count++; }; /* End Not First_Record */ First_Record = FALSE; }; /* End While */ if ( Entry_Count != 0 ) div_curr_ptr = div_prev_ptr; div_curr_ptr->next_ptr = NULL; Stock_Info_Head->Date_Start.Day = Date_Start.Day; Stock_Info_Head->Date_Start.Month = Date_Start.Month; Stock_Info_Head->Date_Start.Year= Date_Start.Year; Stock_Info_Head->Date_End.Day = Date_End.Day; Stock_Info_Head->Date_End.Month = Date_End.Month; Stock_Info_Head->Date_End.Year = Date_End.Year; strcpy ( Stock_Info_Head->Symbol, Symbol ); Stock_Info_Head->Type = Type; Stock_Info_Head->Entry_Count = Entry_Count; Stock_Info_Head->First_Ptr = Stock_Div_Head; Stock_Info_Head->Last_Ptr = div_curr_ptr; url_fclose(handle); return (NULL); /* all done */ } /* End Type Dividend Data Block */ }; /******************************************************************************/ /* */ /* Function: write_callback */ /* */ /******************************************************************************/ /* curl calls this routine to get more data */ static size_t write_callback(char *buffer, size_t size, size_t nitems, void *userp) { char *newbuff; size_t rembuff; URL_FILE *url = (URL_FILE *)userp; size *= nitems; rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ if(size > rembuff) { /* not enough space in buffer */ newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff)); if(newbuff==NULL) { fprintf(stderr,"callback buffer grow failed\n"); size=rembuff; } else { /* realloc suceeded increase buffer size*/ url->buffer_len+=size - rembuff; url->buffer=newbuff; } } memcpy(&url->buffer[url->buffer_pos], buffer, size); url->buffer_pos += size; return size; } /* use to attempt to fill the read buffer up to requested number of bytes */ /******************************************************************************/ /* */ /* Function: fill_buffer */ /* */ /******************************************************************************/ static int fill_buffer(URL_FILE *file, size_t want) { fd_set fdread; fd_set fdwrite; fd_set fdexcep; struct timeval timeout; int rc; /* only attempt to fill buffer if transactions still running and buffer * doesnt exceed required size already */ if((!file->still_running) || (file->buffer_pos > want)) return 0; /* attempt to fill buffer */ do { int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to fail on */ timeout.tv_sec = 60; /* 1 minute */ timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); /* In a real-world program you OF COURSE check the return code of the function calls. On success, the value of maxfd is guaranteed to be greater or equal than -1. We call select(maxfd + 1, ...), specially in case of (maxfd == -1), we call select(0, ...), which is basically equal to sleep. */ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); switch(rc) { case -1: /* select error */ break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform(multi_handle, &file->still_running); break; } } while(file->still_running && (file->buffer_pos < want)); return 1; } /* use to remove want bytes from the front of a files buffer */ /******************************************************************************/ /* */ /* Function: use_buffer */ /* */ /******************************************************************************/ static int use_buffer(URL_FILE *file,int want) { /* sort out buffer */ if((file->buffer_pos - want) <=0) { /* ditch buffer - write will recreate */ if(file->buffer) free(file->buffer); file->buffer=NULL; file->buffer_pos=0; file->buffer_len=0; } else { /* move rest down make it available for later */ memmove(file->buffer, &file->buffer[want], (file->buffer_pos - want)); file->buffer_pos -= want; } return 0; } URL_FILE *url_fopen(const char *url,const char *operation) { /* this code could check for URLs or types in the 'url' and basicly use the real fopen() for standard files */ URL_FILE *file; (void)operation; file = malloc(sizeof(URL_FILE)); if(!file) return NULL; memset(file, 0, sizeof(URL_FILE)); if((file->handle.file=fopen(url,operation))) file->type = CFTYPE_FILE; /* marked as URL */ else { file->type = CFTYPE_CURL; /* marked as URL */ file->handle.curl = curl_easy_init(); curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); if(!multi_handle) multi_handle = curl_multi_init(); curl_multi_add_handle(multi_handle, file->handle.curl); /* lets start the fetch */ curl_multi_perform(multi_handle, &file->still_running); if((file->buffer_pos == 0) && (!file->still_running)) { /* if still_running is 0 now, we should return NULL */ /* make sure the easy handle is not in the multi handle anymore */ curl_multi_remove_handle(multi_handle, file->handle.curl); /* cleanup */ curl_easy_cleanup(file->handle.curl); free(file); file = NULL; } } return file; } /******************************************************************************/ /* */ /* Function: url_fclose */ /* */ /******************************************************************************/ int url_fclose(URL_FILE *file) { int ret=0;/* default is good return */ switch(file->type) { case CFTYPE_FILE: ret=fclose(file->handle.file); /* passthrough */ break; case CFTYPE_CURL: /* make sure the easy handle is not in the multi handle anymore */ curl_multi_remove_handle(multi_handle, file->handle.curl); /* cleanup */ curl_easy_cleanup(file->handle.curl); break; default: /* unknown or supported type - oh dear */ ret=EOF; errno=EBADF; break; } if(file->buffer) free(file->buffer);/* free any allocated buffer space */ free(file); return ret; } /******************************************************************************/ /* */ /* Function: url_feof */ /* */ /******************************************************************************/ int url_feof(URL_FILE *file) { int ret=0; switch(file->type) { case CFTYPE_FILE: ret=feof(file->handle.file); break; case CFTYPE_CURL: if((file->buffer_pos == 0) && (!file->still_running)) ret = 1; break; default: /* unknown or supported type - oh dear */ ret=-1; errno=EBADF; break; } return ret; } /******************************************************************************/ /* */ /* Function: url_fread */ /* */ /******************************************************************************/ size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) { size_t want; switch(file->type) { case CFTYPE_FILE: want=fread(ptr,size,nmemb,file->handle.file); break; case CFTYPE_CURL: want = nmemb * size; fill_buffer(file,want); /* check if theres data in the buffer - if not fill_buffer() * either errored or EOF */ if(!file->buffer_pos) return 0; /* ensure only available data is considered */ if(file->buffer_pos < want) want = file->buffer_pos; /* xfer data to caller */ memcpy(ptr, file->buffer, want); use_buffer(file,want); want = want / size; /* number of items */ break; default: /* unknown or supported type - oh dear */ want=0; errno=EBADF; break; } return want; } /******************************************************************************/ /* */ /* Function: url_fgets */ /* */ /******************************************************************************/ char *url_fgets(char *ptr, size_t size, URL_FILE *file) { size_t want = size - 1;/* always need to leave room for zero termination */ size_t loop; switch(file->type) { case CFTYPE_FILE: ptr = fgets(ptr,size,file->handle.file); break; case CFTYPE_CURL: fill_buffer(file,want); /* check if theres data in the buffer - if not fill either errored or * EOF */ if(!file->buffer_pos) return NULL; /* ensure only available data is considered */ if(file->buffer_pos < want) want = file->buffer_pos; /*buffer contains data */ /* look for newline or eof */ for(loop=0;loop < want;loop++) { if(file->buffer[loop] == '\n') { want=loop+1;/* include newline */ break; } } /* xfer data to caller */ memcpy(ptr, file->buffer, want); ptr[want]=0;/* allways null terminate */ use_buffer(file,want); break; default: /* unknown or supported type - oh dear */ ptr=NULL; errno=EBADF; break; } return ptr;/*success */ } /******************************************************************************/ /* */ /* Function: url_rewind */ /* */ /******************************************************************************/ void url_rewind(URL_FILE *file) { switch(file->type) { case CFTYPE_FILE: rewind(file->handle.file); /* passthrough */ break; case CFTYPE_CURL: /* halt transaction */ curl_multi_remove_handle(multi_handle, file->handle.curl); /* restart */ curl_multi_add_handle(multi_handle, file->handle.curl); /* ditch buffer - write will recreate - resets stream pos*/ if(file->buffer) free(file->buffer); file->buffer=NULL; file->buffer_pos=0; file->buffer_len=0; break; default: /* unknown or supported type - oh dear */ break; } }