/* * 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 #include #include #include #include #include #include #include "recenteditor_data.h" #include "keccak/KeccakHash.h" #define CHUNKSIZE 32768 #define UNSAVEDPREFIX "." #define UNSAVEDPOSTFIX ".reu" 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)); /* data */ redata->sizechunks=0; redata->chunks=NULL; redata->chunkdatasize=CHUNKSIZE; redata->available=0; /* undo */ redata->sizeundo=0; redata->usedundo=0; redata->curundo=0; redata->undo=NULL; redata->undobuf=NULL; /* unsaved */ redata->unsavedfd=-1; redata->flag_unsaveddata=0; /* all done */ return(redata); } void redata_free(redata_t *redata) { int i; if(redata==NULL) return; /* nothing to do */ /* data */ for(i=0;isizechunks;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; /* undo */ if(redata->undo!=NULL) free(redata->undo),redata->undo=NULL; if(redata->undobuf!=NULL) free(redata->undobuf),redata->undobuf=NULL; /* unsaved */ if(redata->unsavedfd!=-1) close(redata->unsavedfd),redata->unsavedfd=-1; if(redata->unsavedfilename!=NULL) { if(redata->unsavedfilename[0]!='\0') { /* remove the file, if here, the user has validated exiting without saving */ unlink(redata->unsavedfilename); } free(redata->unsavedfilename),redata->unsavedfilename=NULL; } /* free main struct */ 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 */ /* data */ for(i=0;isizechunks;i++) { redata->chunks[i]->useddata=0; memset(&(redata->chunks[i]->whatin),0,sizeof(whatin_t)); } redata->available=redata_getsize(redata); /* unsaved */ if(redata->unsavedfd!=-1) close(redata->unsavedfd),redata->unsavedfd=-1; if(redata->unsavedfilename!=NULL) { if(redata->unsavedfilename[0]!='\0') { /* remove the file, if here, the user has validated exiting without saving */ unlink(redata->unsavedfilename); } free(redata->unsavedfilename),redata->unsavedfilename=NULL; } redata->flag_unsaveddata=0; /* all done */ 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;iuseddata=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;idata[i]=='\n')?1:0; } chunk->whatin.nlcount=nlcount; return(0); } int redata_load(redata_t *redata, char *filename, int use_unsaved) { #warning TODO: use_unsaved 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 */ } /* preallocate 10% more than needed */ if(redata_preallocate(redata,statbuf.st_size+(statbuf.st_size/10)+1 )) { if(fd!=-1) close(fd),fd=-1; return(-1); /* insuf. mem. */ } for(totalread=0,chunkno=0,nread=0;totalread=redata->sizechunks || redata->chunks[chunkno]==NULL) { /* alloc another chunk */ if(redata_preallocate(redata,(redata->sizechunks+1)*redata->chunkdatasize)==-1 || 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]; /* leave 10% free on each chunk */ avail=(redata->chunkdatasize-redata->chunkdatasize/10)-chunk->useddata; avail=(avail<0)?0:avail; 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); } /* prepare unsaved */ /* all done */ return(0); } int redata_save(redata_t *redata, char *filename) { #warning TODO return(-1); } int redata_op_add(redata_t *redata, char *buf, int sizebuf, int pos) { } int redata_op_del(redata_t *redata, int pos, int size) { } int redata_op_move(redata_t *redata, int posorig, int size, int posdest) { } int redata_hash(redata_t *redata, char *resbuf129bytes) { static char conv[]={"0123456789ABCDEF"}; Keccak_HashInstance hash; int i,c; if(resbuf129bytes!=NULL) *resbuf129bytes='\0'; if(redata==NULL || resbuf129bytes==NULL) { return(-1); /* sanity check failed */ } if(Keccak_HashInitialize_SHA3_512(&hash)!=SUCCESS) return(-1); /* init failed */ for(i=0;isizechunks;i++) { if(Keccak_HashUpdate(&hash, (void *) redata->chunks[i]->data,redata->chunks[i]->useddata)!=SUCCESS) return(-1); /* hash calc. error */ } if(Keccak_HashFinal(&hash, (void *) resbuf129bytes)!=SUCCESS) { *resbuf129bytes='\0'; return(-1); /* hash final calc. error */ } resbuf129bytes[128]='\0'; for(i=63;i>=0;i--) { c=((unsigned char *)resbuf129bytes)[i]; resbuf129bytes[i<<1]=conv[((c>>4)&0xf)]; resbuf129bytes[(i<<1)+1]=conv[(c&0xf)]; } #warning TODO: result is not as expected return(0); }