Prettied it up a bit.
[stockwidget] / stockgetter.c
1 /*
2  * Simple wrapper for curl and Yahoo finance queries
3  * to enable grabbing stock data.
4  * Jon Parr
5  */
6 #include "stockgetter.h"
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 /* Current maximum query return size */
13 #define SG_MAX_BUFFER 512
14
15 /* Current query string, note the %s for the stock ticker name */
16 #define SG_QUERY_STRING "http://finance.yahoo.com/d/quotes.csv?s=%s&f=l1c"
17
18 static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
19 {
20         StockBuffer *psContext = (StockBuffer*)userp;
21         int nBytes = size * nmemb;
22
23         /*TODO: Write extendable buffer */
24         if(nBytes > psContext->nCount - psContext->nCurr)
25         {
26                 fprintf(stderr,"Ran out of buffer space! (Bytes %d, %d/%d)\n",nBytes,psContext->nCurr,psContext->nCount);
27                 return 0;
28         }
29
30         memcpy((void*)(psContext->pszBuffer + psContext->nCurr),buffer,nBytes);
31         psContext->nCurr += nBytes;
32
33         return nmemb;
34 }
35
36 SGHandle
37 InitStockGetter(void)
38 {
39         SGHandle hSG;
40         CURL *curl_handle;
41
42         hSG = (SGHandle)malloc(sizeof(struct _SGHandle));
43
44         if(!hSG)
45                 return NULL;
46
47         memset(hSG,0,sizeof(struct _SGHandle));
48
49         if(curl_global_init(CURL_GLOBAL_ALL) != 0)
50                 goto err_cleanup;
51
52         curl_handle = curl_easy_init();
53
54         if(!curl_handle)
55                 goto err_cleanup;
56         
57         if(curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION,write_data) != 0)
58                 goto err_cleanup;
59         
60         if(curl_easy_setopt (curl_handle, CURLOPT_FOLLOWLOCATION, 1) != 0)
61                 goto err_cleanup;
62
63         if(curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,&hSG->sData) != 0)
64                 goto err_cleanup;
65                 
66         hSG->hCurlHandle = curl_handle;
67
68         return hSG;
69
70 err_cleanup:
71         
72         if(hSG)
73                 free(hSG);
74         
75         return NULL;
76 }
77
78 int
79 RetrieveStockPrice(SGHandle              hSG,
80                                    char                 *szTicker,
81                                    float                *pfValue,
82                                    float                *pfChangeReal,
83                                    float                *pfChangePercent)
84 {
85         const char      *pszQueryString = SG_QUERY_STRING;
86         char aszQuery[255]              = {0};
87         float           fValue          = 0.0f;
88         float           fChangeReal = 0.0f;
89         float           fChangePer      = 0.0f;
90
91         if(!hSG || !pfValue || !szTicker || strlen(szTicker) > 10)
92                 return SG_INVALID_PARAMS;
93
94         /* On first lookup setup output buffer */
95         if(!hSG->sData.pszBuffer)
96         {
97                 hSG->sData.pszBuffer = (char*)malloc(sizeof(char)*SG_MAX_BUFFER);
98
99                 if(!hSG->sData.pszBuffer)
100                         return SG_BAD_ALLOC;
101
102                 memset(hSG->sData.pszBuffer,0,SG_MAX_BUFFER);
103
104                 hSG->sData.nCount = SG_MAX_BUFFER;
105         }
106         
107         sprintf(aszQuery,pszQueryString,szTicker);
108                 
109         if(curl_easy_setopt(hSG->hCurlHandle, CURLOPT_URL,aszQuery) != 0)
110                 return SG_LOOKUP_FAILURE;
111
112         if(curl_easy_perform(hSG->hCurlHandle) != 0)
113                 return SG_LOOKUP_FAILURE;
114
115         hSG->sData.nCurr = 0;
116         
117         if(sscanf(hSG->sData.pszBuffer,"%f,\"%f - %f\"\n",&fValue,&fChangeReal,&fChangePer) != 3)
118                 return SG_LOOKUP_FAILURE;
119
120         if(pfValue)
121                 *pfValue = fValue;
122
123         if(pfChangeReal)
124                 *pfChangeReal = fChangeReal;
125
126         if(pfChangePercent)
127                 *pfChangePercent = fChangePer;
128
129         return SG_OK;
130 }
131
132 int
133 FreeStockGetter(SGHandle hSG)
134 {
135         if(!hSG)
136                 return SG_INVALID_PARAMS;
137
138         curl_easy_cleanup(hSG->hCurlHandle);
139         curl_global_cleanup();
140
141         free(hSG);
142         
143         return SG_OK;
144 }
145