Listing 1: A stock quote server that uses the EMBSQL library
// 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; }