*
* This example requires libcurl 7.9.7 or later.
*/
+/* <DESC>
+ * implements an fopen() abstraction allowing reading from URLs
+ * </DESC>
+ */
#include <stdio.h>
#include <string.h>
} handle; /* handle */
char *buffer; /* buffer to store cached data*/
- int buffer_len; /* currently allocated buffers length */
- int buffer_pos; /* end of data in buffer*/
+ size_t buffer_len; /* currently allocated buffers length */
+ size_t buffer_pos; /* end of data in buffer*/
int still_running; /* Is background url fetch still in progress */
};
typedef struct fcurl_data URL_FILE;
/* exported functions */
-URL_FILE *url_fopen(const char *url,const char *operation);
+URL_FILE *url_fopen(const char *url, const char *operation);
int url_fclose(URL_FILE *file);
int url_feof(URL_FILE *file);
size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file);
-char * url_fgets(char *ptr, int size, URL_FILE *file);
+char * url_fgets(char *ptr, size_t size, URL_FILE *file);
void url_rewind(URL_FILE *file);
/* we use a global one for convenience */
void *userp)
{
char *newbuff;
- int rembuff;
+ size_t rembuff;
URL_FILE *url = (URL_FILE *)userp;
size *= nitems;
if(size > rembuff) {
/* not enough space in buffer */
- newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff));
+ newbuff=realloc(url->buffer, url->buffer_len + (size - rembuff));
if(newbuff==NULL) {
- fprintf(stderr,"callback buffer grow failed\n");
+ fprintf(stderr, "callback buffer grow failed\n");
size=rembuff;
}
else {
- /* realloc suceeded increase buffer size*/
+ /* realloc succeeded increase buffer size*/
url->buffer_len+=size - rembuff;
url->buffer=newbuff;
}
}
/* use to attempt to fill the read buffer up to requested number of bytes */
-static int fill_buffer(URL_FILE *file,int want,int waittime)
+static int fill_buffer(URL_FILE *file, size_t want)
{
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
struct timeval timeout;
int rc;
+ CURLMcode mc; /* curl_multi_fdset() return code */
/* only attempt to fill buffer if transactions still running and buffer
- * doesnt exceed required size already
+ * doesn't exceed required size already
*/
if((!file->still_running) || (file->buffer_pos > want))
return 0;
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially
- in case of (maxfd == -1), we call select(0, ...), which is basically
- equal to sleep. */
+ if(mc != CURLM_OK) {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
+ no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
+ to sleep 100ms, which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+ if(maxfd == -1) {
+#ifdef _WIN32
+ Sleep(100);
+ rc = 0;
+#else
+ /* Portable sleep for platforms other than Windows. */
+ struct timeval wait = { 0, 100 * 1000 }; /* 100ms */
+ rc = select(0, NULL, NULL, NULL, &wait);
+#endif
+ }
+ else {
+ /* Note that on some platforms 'timeout' may be modified by select().
+ If you need access to the original value save a copy beforehand. */
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
}
/* use to remove want bytes from the front of a files buffer */
-static int use_buffer(URL_FILE *file,int want)
+static int use_buffer(URL_FILE *file, size_t want)
{
/* sort out buffer */
if((file->buffer_pos - want) <=0) {
/* ditch buffer - write will recreate */
- if(file->buffer)
- free(file->buffer);
-
+ free(file->buffer);
file->buffer=NULL;
file->buffer_pos=0;
file->buffer_len=0;
return 0;
}
-URL_FILE *url_fopen(const char *url,const char *operation)
+URL_FILE *url_fopen(const char *url, const char *operation)
{
/* this code could check for URLs or types in the 'url' and
- basicly use the real fopen() for standard files */
+ basically use the real fopen() for standard files */
URL_FILE *file;
(void)operation;
memset(file, 0, sizeof(URL_FILE));
- if((file->handle.file=fopen(url,operation)))
+ if((file->handle.file=fopen(url, operation)))
file->type = CFTYPE_FILE; /* marked as URL */
else {
break;
}
- if(file->buffer)
- free(file->buffer);/* free any allocated buffer space */
-
+ free(file->buffer);/* free any allocated buffer space */
free(file);
return ret;
switch(file->type) {
case CFTYPE_FILE:
- want=fread(ptr,size,nmemb,file->handle.file);
+ want=fread(ptr, size, nmemb, file->handle.file);
break;
case CFTYPE_CURL:
want = nmemb * size;
- fill_buffer(file,want,1);
+ fill_buffer(file, want);
/* check if theres data in the buffer - if not fill_buffer()
* either errored or EOF */
/* xfer data to caller */
memcpy(ptr, file->buffer, want);
- use_buffer(file,want);
+ use_buffer(file, want);
want = want / size; /* number of items */
break;
return want;
}
-char *url_fgets(char *ptr, int size, URL_FILE *file)
+char *url_fgets(char *ptr, size_t size, URL_FILE *file)
{
- int want = size - 1;/* always need to leave room for zero termination */
- int loop;
+ size_t want = size - 1;/* always need to leave room for zero termination */
+ size_t loop;
switch(file->type) {
case CFTYPE_FILE:
- ptr = fgets(ptr,size,file->handle.file);
+ ptr = fgets(ptr, (int)size, file->handle.file);
break;
case CFTYPE_CURL:
- fill_buffer(file,want,1);
+ fill_buffer(file, want);
/* check if theres data in the buffer - if not fill either errored or
* EOF */
memcpy(ptr, file->buffer, want);
ptr[want]=0;/* allways null terminate */
- use_buffer(file,want);
+ use_buffer(file, want);
break;
curl_multi_add_handle(multi_handle, file->handle.curl);
/* ditch buffer - write will recreate - resets stream pos*/
- if(file->buffer)
- free(file->buffer);
-
+ free(file->buffer);
file->buffer=NULL;
file->buffer_pos=0;
file->buffer_len=0;
}
}
+#define FGETSFILE "fgets.test"
+#define FREADFILE "fread.test"
+#define REWINDFILE "rewind.test"
+
/* Small main program to retrive from a url using fgets and fread saving the
* output to two test files (note the fgets method will corrupt binary files if
* they contain 0 chars */
URL_FILE *handle;
FILE *outf;
- int nread;
+ size_t nread;
char buffer[256];
const char *url;
url=argv[1];/* use passed url */
/* copy from url line by line with fgets */
- outf=fopen("fgets.test","w+");
+ outf=fopen(FGETSFILE, "wb+");
if(!outf) {
perror("couldn't open fgets output file\n");
return 1;
}
while(!url_feof(handle)) {
- url_fgets(buffer,sizeof(buffer),handle);
- fwrite(buffer,1,strlen(buffer),outf);
+ url_fgets(buffer, sizeof(buffer), handle);
+ fwrite(buffer, 1, strlen(buffer), outf);
}
url_fclose(handle);
/* Copy from url with fread */
- outf=fopen("fread.test","w+");
+ outf=fopen(FREADFILE, "wb+");
if(!outf) {
perror("couldn't open fread output file\n");
return 1;
}
do {
- nread = url_fread(buffer, 1,sizeof(buffer), handle);
- fwrite(buffer,1,nread,outf);
+ nread = url_fread(buffer, 1, sizeof(buffer), handle);
+ fwrite(buffer, 1, nread, outf);
} while(nread);
url_fclose(handle);
/* Test rewind */
- outf=fopen("rewind.test","w+");
+ outf=fopen(REWINDFILE, "wb+");
if(!outf) {
perror("couldn't open fread output file\n");
return 1;
return 2;
}
- nread = url_fread(buffer, 1,sizeof(buffer), handle);
- fwrite(buffer,1,nread,outf);
+ nread = url_fread(buffer, 1, sizeof(buffer), handle);
+ fwrite(buffer, 1, nread, outf);
url_rewind(handle);
buffer[0]='\n';
- fwrite(buffer,1,1,outf);
-
- nread = url_fread(buffer, 1,sizeof(buffer), handle);
- fwrite(buffer,1,nread,outf);
+ fwrite(buffer, 1, 1, outf);
+ nread = url_fread(buffer, 1, sizeof(buffer), handle);
+ fwrite(buffer, 1, nread, outf);
url_fclose(handle);
fclose(outf);
-
return 0;/* all done */
}