--- /dev/null
+/*
+ * Simple wrapper for curl and Yahoo finance queries
+ * to enable grabbing stock data.
+ * Jon Parr
+ */
+#include "stockgetter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Current maximum query return size */
+#define SG_MAX_BUFFER 512
+
+/* Current query string, note the %s for the stock ticker name */
+#define SG_QUERY_STRING "http://finance.yahoo.com/d/quotes.csv?s=%s&f=l1c"
+
+static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
+{
+ StockBuffer *psContext = (StockBuffer*)userp;
+ int nBytes = size * nmemb;
+
+ /*TODO: Write extendable buffer */
+ if(nBytes > psContext->nCount - psContext->nCurr)
+ {
+ fprintf(stderr,"Ran out of buffer space! (Bytes %d, %d/%d)\n",nBytes,psContext->nCurr,psContext->nCount);
+ return 0;
+ }
+
+ memcpy((void*)(psContext->pszBuffer + psContext->nCurr),buffer,nBytes);
+ psContext->nCurr += nBytes;
+
+ return nmemb;
+}
+
+SGHandle
+InitStockGetter(void)
+{
+ SGHandle hSG;
+ CURL *curl_handle;
+
+ hSG = (SGHandle)malloc(sizeof(struct _SGHandle));
+
+ if(!hSG)
+ return NULL;
+
+ memset(hSG,0,sizeof(struct _SGHandle));
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != 0)
+ goto err_cleanup;
+
+ curl_handle = curl_easy_init();
+
+ if(!curl_handle)
+ goto err_cleanup;
+
+ if(curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION,write_data) != 0)
+ goto err_cleanup;
+
+ if(curl_easy_setopt (curl_handle, CURLOPT_FOLLOWLOCATION, 1) != 0)
+ goto err_cleanup;
+
+ if(curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,&hSG->sData) != 0)
+ goto err_cleanup;
+
+ hSG->hCurlHandle = curl_handle;
+
+ return hSG;
+
+err_cleanup:
+
+ if(hSG)
+ free(hSG);
+
+ return NULL;
+}
+
+int
+RetrieveStockPrice(SGHandle hSG,
+ char *szTicker,
+ float *pfValue,
+ float *pfChangeReal,
+ float *pfChangePercent)
+{
+ const char *pszQueryString = SG_QUERY_STRING;
+ char aszQuery[255] = {0};
+ float fValue = 0.0f;
+ float fChangeReal = 0.0f;
+ float fChangePer = 0.0f;
+
+ if(!hSG || !pfValue || !szTicker || strlen(szTicker) > 10)
+ return SG_INVALID_PARAMS;
+
+ /* On first lookup setup output buffer */
+ if(!hSG->sData.pszBuffer)
+ {
+ hSG->sData.pszBuffer = (char*)malloc(sizeof(char)*SG_MAX_BUFFER);
+
+ if(!hSG->sData.pszBuffer)
+ return SG_BAD_ALLOC;
+
+ memset(hSG->sData.pszBuffer,0,SG_MAX_BUFFER);
+
+ hSG->sData.nCount = SG_MAX_BUFFER;
+ }
+
+ sprintf(aszQuery,pszQueryString,szTicker);
+
+ if(curl_easy_setopt(hSG->hCurlHandle, CURLOPT_URL,aszQuery) != 0)
+ return SG_LOOKUP_FAILURE;
+
+ if(curl_easy_perform(hSG->hCurlHandle) != 0)
+ return SG_LOOKUP_FAILURE;
+
+ hSG->sData.nCurr = 0;
+
+ if(sscanf(hSG->sData.pszBuffer,"%f,\"%f - %f\"\n",&fValue,&fChangeReal,&fChangePer) != 3)
+ return SG_LOOKUP_FAILURE;
+
+ if(pfValue)
+ *pfValue = fValue;
+
+ if(pfChangeReal)
+ *pfChangeReal = fChangeReal;
+
+ if(pfChangePercent)
+ *pfChangePercent = fChangePer;
+
+ return SG_OK;
+}
+
+int
+FreeStockGetter(SGHandle hSG)
+{
+ if(!hSG)
+ return SG_INVALID_PARAMS;
+
+ curl_easy_cleanup(hSG->hCurlHandle);
+ curl_global_cleanup();
+
+ free(hSG);
+
+ return SG_OK;
+}
+