/* * recenteditor_data.c * * A programmers editor * * Structures to hold the current file contents. * * Author: Dario Rodriguez dario@softhome.net * This program is licensed under the terms of GNU GPL v2.1+ */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "recenteditor_data.h" #define CHUNKSIZE 32768 redata_t * redata_init(void) { redata_t *redata; if((redata=malloc(sizeof(redata_t)))==NULL) return(NULL); /* sanity check failed */ memset(redata,0,sizeof(redata_t)); redata->sizechunks=0; redata->chunks=NULL; redata->chunkdatasize=CHUNKSIZE; redata->available=0; return(redata); } void redata_free(redata_t *redata) { int i; if(redata==NULL) return; /* nothing to do */ for(i=0;i<redata->sizechunks;i++) { if(redata->chunks[i]!=NULL) free(redata->chunks[i]),redata->chunks[i]=NULL; } redata->sizechunks=0; if(redata->chunks!=NULL) free(redata->chunks),redata->chunks=NULL; free(redata),redata=NULL; return; } int redata_getsize(redata_t *redata) { if(redata==NULL) return(0); /* sanity check failed */ return(redata->chunkdatasize*redata->sizechunks); } int redata_getused(redata_t *redata) { if(redata==NULL) return(0); /* sanity check failed */ return(redata_getsize(redata)-redata_getavailable(redata)); } int redata_getavailable(redata_t *redata) { if(redata==NULL) return(0); /* sanity check failed */ return(redata->available); } int redata_wipe(redata_t *redata) { int i; if(redata==NULL) return(-1); /* sanity check failed */ for(i=0;i<redata->sizechunks;i++) { redata->chunks[i]->useddata=0; memset(&(redata->chunks[i]->whatin),0,sizeof(whatin_t)); } redata->available=redata_getsize(redata); return(0); } int redata_preallocate(redata_t *redata, int newsize) { int cursize; int nchunks; int i; int rechunksize; rechunk_t *newchunks,*chunk; int oldsizechunks; if(redata==NULL || redata->chunkdatasize==0 || newsize<0) return(-1); /* sanity check failed */ if((cursize=redata_getsize(redata))>=newsize) return(0); /* all done */ nchunks=(newsize-cursize+redata->chunkdatasize-1)/redata->chunkdatasize; rechunksize=sizeof(rechunk_t)-1+redata->chunkdatasize; if((newchunks=realloc(redata->chunks,sizeof(rechunk_t *)*(redata->sizechunks+nchunks)))==NULL) return(-1); /* insuf. mem. */ redata->chunks=newchunks; memset(redata->chunks+redata->sizechunks,0,sizeof(rechunk_t *)*nchunks); oldsizechunks=redata->sizechunks; for(i=0;i<nchunks;i++) { if((chunk=malloc(rechunksize))==NULL) return(-1); /* insuf. mem. */ memset(chunk,0,rechunksize); chunk->useddata=0; redata->chunks[oldsizechunks+i]=chunk; redata->sizechunks++; redata->available+=redata->chunkdatasize; } return(0); } int redata_fill_whatin(redata_t *redata, int chunkno) { rechunk_t *chunk; int nlcount; int i,lim; if(redata==NULL || chunkno<0 || chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) return(-1); /* sanity check failed */ chunk=redata->chunks[chunkno]; memset(&(chunk->whatin),0,sizeof(whatin_t)); nlcount=0; for(i=0,lim=chunk->useddata;i<lim;i++) { nlcount+=(chunk->data[i]=='\n')?1:0; } chunk->whatin.nlcount=nlcount; return(0); } int redata_load(redata_t *redata, char *filename) { int fd,nread,totalread; int chunkno, avail; struct stat statbuf; rechunk_t *chunk; redata_wipe(redata); if((fd=open(filename,O_RDONLY))==-1 || fstat(fd,&statbuf)!=0 || !S_ISREG(statbuf.st_mode)) { if(fd!=-1) close(fd),fd=-1; return(-1); /* file not found, couldn't query size or not regular file */ } if(redata_preallocate(redata,statbuf.st_size)) { if(fd!=-1) close(fd),fd=-1; return(-1); /* insuf. mem. */ } for(totalread=0,chunkno=0,nread=0;totalread<statbuf.st_size;totalread+=nread,nread=0) { if(chunkno>=redata->sizechunks || redata->chunks[chunkno]==NULL) { if(fd!=-1) close(fd),fd=-1; fprintf(stderr,"redata_load: INTERNAL ERROR\n"); return(-2); /* internal error */ } chunk=redata->chunks[chunkno]; avail=redata->chunkdatasize-chunk->useddata; avail=((totalread+avail)>statbuf.st_size)?statbuf.st_size-totalread:avail; if(avail==0) { chunkno++; /* full, try next */ continue; } if((nread=read(fd,chunk->data+chunk->useddata,avail))<=0) { if(fd!=-1) close(fd),fd=-1; return(-1); /* short read */ } chunk->useddata+=nread; redata->available-=nread; redata_fill_whatin(redata,chunkno); } return(0); } int redata_save(redata_t *redata, char *filename) { #warning TODO return(-1); }