Back to index

avfs  1.0.1
filebuf.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998-2001  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 /* filebuf.c
00009    
00010    Implements buffered i/o with avfs fs functions. Includes facilities
00011    for i/o multiplexing as well.
00012 */
00013 
00014 #include "filebuf.h"
00015 
00016 #include <fcntl.h>
00017 #include <unistd.h>
00018 #include <poll.h>
00019 
00020 struct filebuf {
00021     int flags;
00022     int fd;
00023     avsize_t size;
00024     avsize_t ptr;
00025     avsize_t nbytes;
00026     char *buf;
00027     int eof;
00028     int avail;
00029 };
00030 
00031 static void free_filebuf(struct filebuf *fb)
00032 {
00033     av_free(fb->buf);
00034     close(fb->fd);
00035 }
00036 
00037 struct filebuf *av_filebuf_new(int fd, int flags)
00038 {
00039     struct filebuf *fb;
00040     int oflags;
00041 
00042     AV_NEW_OBJ(fb, free_filebuf);
00043 
00044     if(flags & FILEBUF_NONBLOCK) {
00045         oflags = fcntl(fd, F_GETFL);
00046         oflags = oflags == -1 ? 0 : oflags;
00047         fcntl(fd, F_SETFL, oflags | O_NONBLOCK);
00048     }
00049 
00050     fb->flags = flags;
00051     fb->fd = fd;
00052     fb->size = 0;
00053     fb->nbytes = 0;
00054     fb->ptr = 0;
00055     fb->buf = NULL;
00056     fb->eof = 0;
00057     fb->avail = 0;
00058 
00059     return fb;
00060 }
00061 
00062 int av_filebuf_eof(struct filebuf *fb)
00063 {
00064     return fb->eof;
00065 }
00066 
00067 static void filebuf_fill_poll(struct filebuf *fbs[], struct pollfd *pf,
00068                               int numfbs)
00069 {
00070     int i;
00071 
00072     for(i = 0; i < numfbs; i++) {
00073         pf[i].fd = -1;
00074         pf[i].events = 0;
00075         if(fbs[i] != NULL && !fbs[i]->eof) {
00076             pf[i].fd = fbs[i]->fd;
00077             if((fbs[i]->flags & FILEBUF_WRITE) != 0)
00078                 pf[i].events = POLLOUT;
00079             else
00080                 pf[i].events = POLLIN;
00081         }
00082     }
00083 }
00084 
00085 static void filebuf_check_poll(struct filebuf *fbs[], struct pollfd *pf,
00086                                int numfbs)
00087 {
00088     int i;
00089 
00090     for(i = 0; i < numfbs; i++) {
00091         if(fbs[i] != NULL && !fbs[i]->eof) {
00092             if(pf[i].revents != 0)
00093                 fbs[i]->avail = 1;
00094             else
00095                 fbs[i]->avail = 0;
00096         }
00097     }
00098 }
00099                                
00100 int av_filebuf_check(struct filebuf *fbs[], unsigned int numfbs,
00101                        long timeoutms)
00102 {
00103     int res;
00104     struct pollfd *pf;
00105 
00106     pf = (struct pollfd *) av_malloc(sizeof(*pf) * numfbs);
00107     filebuf_fill_poll(fbs, pf, numfbs);
00108     res = poll(pf, numfbs, timeoutms);
00109     if(res == -1) {
00110         av_log(AVLOG_ERROR, "filebuf: poll error: %s", strerror(errno));
00111         res = -EIO;
00112     }
00113     else if(res > 0) {
00114         filebuf_check_poll(fbs, pf, numfbs);
00115         res = 1;
00116     }
00117     av_free(pf);
00118 
00119     return res;
00120 }
00121 
00122 static avssize_t filebuf_real_read(struct filebuf *fb, char *buf,
00123                                    avsize_t nbytes)
00124 {
00125     avssize_t res;
00126 
00127     if(!fb->avail)
00128         return 0;
00129 
00130     fb->avail = 0;
00131     res = read(fb->fd, buf, nbytes);
00132     if(res < 0) {
00133         av_log(AVLOG_ERROR, "filebuf: read error: %s", strerror(errno));
00134         return -EIO;
00135     }
00136     if(res == 0)
00137         fb->eof = 1;
00138 
00139     return res;
00140 }
00141 
00142 avssize_t av_filebuf_read(struct filebuf *fb, char *buf, avsize_t nbytes)
00143 {
00144     if(fb->nbytes > 0) {
00145         avsize_t nact = AV_MIN(fb->nbytes, nbytes);
00146         
00147         memcpy(buf, fb->buf + fb->ptr, nact);
00148         fb->ptr += nact;
00149         fb->nbytes -= nact;
00150 
00151         return nact;
00152     }
00153 
00154     return  filebuf_real_read(fb, buf, nbytes);
00155 }
00156 
00157 avssize_t av_filebuf_write(struct filebuf *fb, const char *buf,
00158                              avsize_t nbytes)
00159 {
00160     avssize_t res;
00161 
00162     if(!fb->avail)
00163         return 0;
00164 
00165     fb->avail = 0;
00166     res = write(fb->fd, buf, nbytes);
00167     if(res < 0) {
00168         av_log(AVLOG_ERROR, "filebuf: write error: %s", strerror(errno));
00169         return -EIO;
00170     }
00171 
00172     return res;
00173 }
00174 
00175 static avssize_t read_data(struct filebuf *fb)
00176 {
00177     avssize_t res;
00178     const int readsize = 256;
00179     avsize_t newsize;
00180 
00181     if(fb->ptr != 0 && fb->nbytes != 0)
00182         memmove(fb->buf, fb->buf + fb->ptr, fb->nbytes);
00183         
00184     fb->ptr = 0;
00185     
00186     newsize = fb->nbytes + readsize;
00187     if(newsize > fb->size) {
00188         fb->buf = av_realloc(fb->buf, newsize);
00189         fb->size = newsize;
00190     }
00191     
00192     res = filebuf_real_read(fb, fb->buf + fb->nbytes, readsize);
00193     if(res > 0)
00194         fb->nbytes += res;
00195 
00196     return res;
00197 }
00198 
00199 static avssize_t filebuf_lineend(struct filebuf *fb)
00200 {
00201     avssize_t res;
00202     char *start;
00203     char *s;
00204 
00205     do {
00206         start = fb->buf + fb->ptr;
00207         if(fb->nbytes > 0) {
00208             s = memchr(start, '\n', fb->nbytes);
00209             if(s != NULL)
00210                 return (s + 1) - start;
00211         }
00212 
00213         if(fb->eof)
00214             return fb->nbytes;
00215         
00216         res = read_data(fb);
00217     } while(res > 0);
00218 
00219     return res;
00220 }
00221 
00222 int av_filebuf_readline(struct filebuf *fb, char **resp)
00223 {
00224     avssize_t nbytes;
00225 
00226     *resp = NULL;
00227 
00228     nbytes = filebuf_lineend(fb);
00229     if(nbytes <= 0)
00230         return nbytes;
00231     
00232     *resp = av_strndup(fb->buf + fb->ptr, nbytes);
00233 
00234     fb->ptr += nbytes;
00235     fb->nbytes -= nbytes;
00236 
00237     return 1;
00238 }
00239 
00240 int av_filebuf_getline(struct filebuf *fb, char **linep, long timeoutms)
00241 {
00242     int res;
00243     char *line;
00244 
00245     *linep = NULL;
00246     while(1) {
00247         res = av_filebuf_readline(fb, &line);
00248         if(res < 0)
00249             return res;
00250         if(res == 1)
00251             break;
00252 
00253         if(av_filebuf_eof(fb))
00254             return 1;
00255 
00256         res = av_filebuf_check(&fb, 1, timeoutms);
00257         if(res < 0)
00258             return res;
00259 
00260         if(res == 0) 
00261             return 0;
00262     }
00263 
00264     *linep = line;
00265 
00266     return 1;
00267 }