Added initial revision of stock widget to repo.
[stockwidget] / stockgetter.c
diff --git a/stockgetter.c b/stockgetter.c
new file mode 100644 (file)
index 0000000..de13724
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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;
+}
+