// LOADSTOCKS Server program: get stocks from quote.yahoo.com
// and load them into a Memory based Embedded SQL object
#include <afxwin.h>
#include <winsock.h>
#include <iostream.h>
#include "EMBSQL.h"
static SOCKET ConnectToTcp(char *host, int port);
static BOOL Select(SOCKET fd, int secs); // select a socket
static void bcopy(char *s, char *d, int n); // unix style copy
static void bzero(char *s, int n); // unix style zero
static int Initialize(); // init the network
// decompose the HTTP back from yahoo
static void Decompose(CString buf, CESql*,BOOL);
// Format of the HTTP get for retrieving a stock quote
#define spec "GET /d/quotes.csv?s=%s&f=sl1d1t1c1ohgv&e=.csv \
HTTP/1.0\r\nUser-Agent: http-get/0.1\r\n\r\n"
void TestSelect();
void main(int argc, char *argv[])
{
SOCKET port = 0; // yahoo's quote server port;
int i = 0, len = 0;
char buf[512] = ""; // network read/write buffer
CESql* dBase = NULL; // pointer to the embsql object
BOOL first = true; // first time insert, then update
if (!Initialize())
perror(argv[0]);
dBase = new CESql(); // construct & def table structure
dBase->Sql("CREATE TABLE stocks (\
SYMBOL char(8), \
DATE char(9), \
TIME char(6), \
HIGH float, \
LOW float, \
LAST float, \
VOLUME float)");
while(1) {
for (i=1;i<argc;i++) {
// Get the web port
port = ConnectToTcp("quote.yahoo.com",80);
if (port == 0) {
cout << "Can't connect to Yahoo!\n";
exit(1);
}
// format the cgi query
sprintf(buf,spec,argv[i]);
len = strlen(buf);
if (send(port,(char *)buf,len,0) <= 0) { // transmit
cout << "Error requesting info for " << buf;
exit(1);
}
// get the response from the web-server, Don't block
if (!Select(port,5)) { // wait up to 5 seconds
cout << "Web server timed out! Bye!\n";
exit(1);
}
len = recv(port,(char *)buf,512,0);
if (len <= 0) {
cout << "Error retriving info for " << buf;
exit(1);
}
if (strstr(buf,"HTTP/1.0 200 OK") == NULL) {
cout << "Error: " << buf;
exit(1);
}
// parse the html & Do SQL
Decompose(CString(buf),dBase,first);
closesocket(port);
}
if (first)
first = false; // next, do SQL update, not insert
Sleep(60000 * 5); // sleep 5 minutes
}
}
// Decomposes an HTML page containing a stock quote. The first
// param, buf, has HTML page. Creates an array of values:
// [0] = ticker
// [1] = Last
// [2] = Date
// [3] = Time
// [4] = Change
// [5] = Open
// [6] = Day's High
// [7] = Day's low
// [8] = Volume
// Using these values either an SQL insert or update command is,
// executed via the dBase's Sql() method, as defined by the
// param 'insert'.
static void Decompose(CString buf, CESql* dBase, BOOL insert)
{
CString tokenString, value, values[10], cmd = "";
int i = 0;
tokenString = buf.SpanExcluding("\""); // break apart
buf = buf.Mid(tokenString.GetLength());
tokenString = buf.SpanExcluding("\r");
// Load the array
while((value = tokenString.SpanExcluding(",")) !=
tokenString) {
tokenString = tokenString.Mid(value.GetLength()+1);
if (value[0] == '"') {
value = value.Mid(1,value.GetLength()-2);
value = "'" + value + "'";
}
values[i++] = value;
}
values[i++] = tokenString;
// Format the SQL command, depending on 'insert'
if (insert)
cmd = "INSERT INTO STOCKS \
(SYMBOL,DATE,TIME,LAST,HIGH,LOW,VOLUME) \
VALUES(" +
values[0] + "," +
values[2] + "," +
values[3] + "," +
values[1] + "," +
values[6] + "," +
values[7] + "," +
values[8] + ")";
else
cmd = "UPDATE STOCKS SET(DATE=" + values[2] + "," +
"TIME =" + values[3] + "," +
"LAST =" + values[1] + "," +
"HIGH =" + values[6] + "," +
"LOW =" + values[7] + "," +
"VOLUME=" + values[8] +") WHERE SYMBOL=" +
values[0];
if (dBase->Sql(cmd) == NULL) {
cout << "ERROR: " + dBase->ReturnError();
exit(1);
}
cout << cmd << "\n";
cout.flush();
}
//
// Make and connect to TCP socket
static SOCKET ConnectToTcp(char *host, int port)
{
struct sockaddr_in new_sock;
struct hostent *hp;
int rc, xc;
u_long mode;
bzero((char *)&new_sock, sizeof(new_sock));
new_sock.sin_family = AF_INET;
new_sock.sin_port = htons(port);
hp = gethostbyname(host); // get the hostent pointer
if (hp == NULL) {
cout << "No such name: " << host;
return 0;
}
// set up the IP structure using the address and port
bcopy((char *)hp->h_addr, (char *)&new_sock.sin_addr,
hp->h_length);
// get a TCP socket
rc = socket(AF_INET, SOCK_STREAM, 0);
if (rc < 0) {
perror("ConnectToTcp::socket");
return 0;
}
mode = 0;
// make socket non-blocking
ioctlsocket(rc,FIONBIO,&mode);
// connect to the web server defined by 'host'
xc = connect(rc, (struct sockaddr*)&new_sock,
sizeof(new_sock));
if (xc == 0)
return(rc);
return 0;
}
static BOOL Select(SOCKET fd, int sec)
{
static fd_set testSet;
struct timeval tval;
tval.tv_usec = 0;
tval.tv_sec = sec;
FD_ZERO(&testSet);
FD_SET(fd, &testSet);
if (select(fd+1, &testSet, 0, 0, &tval) <= 0)
return FALSE;
return TRUE;
}
//
// UNIX style byte copy
static void bcopy(char *s, char *d, int n)
{
for (int i=0;i<n;i++) d[i] = s[i];
}
//
// UNIX style zero buffer
static void bzero(char *s, int n)
{
for (int i=0;i<n;i++) s[i] = 0;
}
//
// Initialize winsock
//
static int Initialize()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );// version >= 1.1
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
return 0;
return 1;
}