/* WebDownloader for X-Window
* Copyright (C) 1999-2002 Koshelev Maxim
* This Program is free but not GPL!!! You can't modify it
* without agreement with author. You can't distribute modified
* program but you can distribute unmodified program.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "segments.h"
#include "dbc.h"
#include "signal.h"
#include "locstr.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
tSegment::tSegment(){
begin=end=0;
};
void tSegment::print(){
printf("%.12Lu %.12Lu\n",begin,end);
};
int tSegment::save(int fd){
DBC_RETVAL_IF_FAIL(fd>=0,-1);
if (write(fd,&begin,sizeof(begin))!=int(sizeof(begin)) ||
write(fd,&end,sizeof(end))!=int(sizeof(end)))
return(-1);
return(0);
};
tSegment::~tSegment(){
// do nothing?
};
/*************** Segmentator *************************************/
tSegmentator::tSegmentator(){
FIRST=LAST=HEAP=NULL;
fd=-1;
filename=NULL;
};
tSegmentator::tSegmentator(char *path){
FIRST=LAST=HEAP=NULL;
filename=NULL;
fd=-1;
total=0;
init(path);
};
tSegment *tSegmentator::seg_alloc(){
if (HEAP){
tSegment *rval=HEAP;
HEAP=HEAP->next;
return(rval);
};
return(new tSegment);
};
void tSegmentator::seg_free(tSegment *seg){
seg->next=HEAP;
HEAP=seg;
};
void tSegmentator::init(char *path){
DBC_RETURN_IF_FAIL(path!=NULL);
done();
autosave_counter=50;
filename=copy_string(path);
fd=open(path, O_CREAT|O_RDWR,S_IRUSR | S_IWUSR);
load();
// print();
};
void tSegmentator::print(){
tSegment *tmp=FIRST;
while(tmp){
tmp->print();
tmp=tmp->next;
};
printf("total %Lu -----------------\n",total);
};
segoff_t tSegmentator::get_total(){
return(total);
};
/* tSegmentator::insert
return values:
zero - if inserted zone does not overlap any exist zone
non zero - if it overlaps :-)
*/
int tSegmentator::insert(segoff_t begin, segoff_t end){
if (begin>=end) return(0); //simple case :-)
//FIXME: overlapping only below, overlapping above is not overlapping;
// [100-200] + [201-300] = not overlapped
// [100-200] + [0-99] = not overlapped
// [100-200] + [100-300] = not overlapped
// [100-200] + [101-102] = overlapped
// [100-200] + [50-150] = overlapped
lock();
int rval=0;
if (FIRST){
tSegment *cur=FIRST;
tSegment *prev=NULL;
while(cur && cur->end+1<begin){
prev=cur;
cur=cur->next;
};
if (cur){ //somewhere in the list
if (cur->begin>end+1){ //just insert new element here
tSegment *add=seg_alloc();
if ((add->prev=prev))
prev->next=add;
else
FIRST=add;
add->next=cur;
cur->prev=add;
add->begin=begin;
add->end=end;
total+=end-begin;
}else{
segoff_t dec=cur->end-cur->begin;
if ((cur->begin>=begin && cur->begin<end)||
cur->end>end)
rval=1;
if (cur->begin>begin)
cur->begin=begin;
if (cur->end<end)
cur->end=end;
//proceed compactifation
while(cur->next){
tSegment *next=cur->next;
if (next->begin<=cur->end+1){ //remove next element as overlaped
dec+=next->end-next->begin;
if (cur->end<next->end)
cur->end=next->end;
if ((cur->next=next->next))
cur->next->prev=cur;
else
LAST=cur;
seg_free(next);
}else
break;
};
total+=cur->end-cur->begin-dec;
};
}else{ // at the end of the list
tSegment *add=seg_alloc();
add->next=NULL;
LAST->next=add;
add->prev=LAST;
LAST=add;
add->begin=begin;
add->end=end;
total+=end-begin;
};
}else{
FIRST=LAST=seg_alloc();
FIRST->next=FIRST->prev=NULL;
FIRST->begin=begin;
FIRST->end=end;
total=end-begin;
};
if (autosave_counter--<0){
autosave_counter=50;
save();
};
unlock();
return(rval);
};
tSegment *tSegmentator::get_first(){
return(FIRST);
};
int tSegmentator::one_segment(){
if (FIRST==NULL || FIRST->next==NULL) return 1;
return 0;
};
void tSegmentator::truncate(segoff_t shift){
lock();
tSegment *tmp=FIRST;
total=0;
while(tmp){
tSegment *next=tmp->next;
if (tmp->begin>=shift){
if (tmp->prev)
tmp->prev->next=NULL;
else
FIRST=NULL;
seg_free(tmp);
}else{
if (tmp->end>=shift)
tmp->end=shift;
total+=tmp->end-tmp->begin;
};
tmp=next;
};
save();
unlock();
};
void tSegmentator::done(){
lock();
total=0;
if (filename){
delete[] filename;
filename=NULL;
};
while(FIRST){
tSegment *tmp=(tSegment*)FIRST->next;
seg_free(FIRST);
FIRST=tmp;
};
if (fd>=0) close(fd);
fd=-1;
unlock();
};
void tSegmentator::complete(){
if (filename)
::remove(filename);
if (FIRST){
lock();
tSegment *a=seg_alloc();
a->begin=FIRST->begin;
a->end=LAST->end;
a->next=a->prev=NULL;
unlock();
done();
FIRST=LAST=a;
total=a->end-a->begin;
};
};
tSegmentator::~tSegmentator(){
done();
while(HEAP){
tSegment *tmp=HEAP->next;
delete(HEAP);
HEAP=tmp;
};
if (filename) delete[] filename;
};
/* private methods */
int tSegmentator::load(){
DBC_RETVAL_IF_FAIL(fd>=0,-1);
lseek(fd,0,SEEK_SET);
segoff_t begin,end;
while(read(fd,&begin,sizeof(begin))==sizeof(begin) &&
read(fd,&end,sizeof(end))==sizeof(end)){
insert(begin,end);
};
return (0);
};
int tSegmentator::save(){
DBC_RETVAL_IF_FAIL(fd>=0,-1);
tSegment *tmp=FIRST;
lseek(fd,0,SEEK_SET);
ftruncate(fd,0);
while(tmp){
if (tmp->save(fd)) return(-1);
tmp=tmp->next;
};
return(0);
};
tSegment *tSegmentator::to_holes(segoff_t size){
lock();
tSegment *tmp=FIRST;
tSegment *rvalue=NULL;
tSegment *last=NULL;
int i=0;
while(tmp && tmp->end<size){
tSegment *tmp1=new tSegment;
tmp1->begin=tmp->end;
if (tmp->next){
tmp1->end=tmp->next->begin;
}else{
tmp1->end=size;
};
i+=1;
tmp1->next=NULL;
if (last)
last->next=tmp1;
else
rvalue=tmp1;
last=tmp1;
tmp=tmp->next;
};
if (rvalue==NULL){
rvalue=new tSegment;
rvalue->begin=0;
rvalue->end=size;
rvalue->offset_in_file=1;
rvalue->next=NULL;
}else{
rvalue->offset_in_file=i;
};
unlock();
return(rvalue);
};
void tSegmentator::lock_public(){
lockmutex.lock();
};
void tSegmentator::unlock_public(){
lockmutex.unlock();
};
void tSegmentator::lock(){
lockmutex.lock();
};
void tSegmentator::unlock(){
lockmutex.unlock();
};
syntax highlighted by Code2HTML, v. 0.9.1