#include #include #include #include #include #include #include #include extern const char *__progname; #include "seq.h" #include "accum.h" #include "folder.h" #include "system.h" #include "deconst.h" #include "profile.h" #include "message.h" struct mm_seqs { FOLDER *f; unsigned int dirty : 1; SEQ *seqs; void *resvn; const char *pathname; int fd; } ; struct mm_seq { SEQ *link; SEQS *list; const char *name; int size; int nranges; int (*ranges)[2]; int nalloc; } ; static int any_nonempty_seqs(SEQ *s) { for (;s;s=s->link) if (s->nranges > 0) return(1); return(0); } static void load_seqfile(FILE *f, SEQS *ss) { ACCUM *a; char ch; int c; int c2; SEQ *s; while (1) { nextline:; if (fscanf(f," %c",&ch) != 1) break; ungetc(ch,f); a = accum_init(ACCUM_NULLTERM); while (1) { c = getc(f); if (c == EOF) goto out; /* break 2 */ if (c == '\n') { accum_free(a); goto nextline; /* continue 2 */ } if (c == ':') break; if (! isspace(c)) accum_char(a,c); } s = seq_lookup(ss,accum_buf(a)); accum_free(a); while (1) { do c = getc(f); while ((c != EOF) && (c != '\n') && isspace(c)); if ((c == EOF) || (c == '\n')) break; ungetc(c,f); if (fscanf(f,"%d",&c) != 1) { c = getc(f); break; } seq_add(s,c); c2 = getc(f); if (c2 == '-') { if (fscanf(f,"%d",&c2) != 1) { c = getc(f); break; } seq_add_range(s,c,c2); } else if (c2 == EOF) { break; } else { ungetc(c2,f); } } while ((c != '\n') && (c != EOF)) c = getc(f); if (c == EOF) break; } out:; } static void dump_seqfile(FILE *f, SEQS *ss) { SEQ *s; int i; for (s=ss->seqs;s;s=s->link) { if (s->nranges < 1) continue; fprintf(f,"%s:",s->name); for (i=0;inranges;i++) { int *r; r = &s->ranges[i][0]; if (r[0] == r[1]) { fprintf(f," %d",r[0]); } else { fprintf(f," %d-%d",r[0],r[1]); } } fprintf(f,"\n"); } } static void insert_range(SEQ *s, int at) { if ((at < 0) || (at > s->nranges)) abort(); if (s->nranges >= s->nalloc) s->ranges = realloc(s->ranges,(s->nalloc=s->nranges+8)*sizeof(*s->ranges)); if (at < s->nranges) bcopy(s->ranges+at,s->ranges+at+1,(s->nranges-at)*sizeof(*s->ranges)); s->nranges ++; } static void delete_ranges(SEQ *s, int at, int n) { if ((at < 0) || (n < 0) || (at+n > s->nranges)) abort(); if (at+n < s->nranges) bcopy(s->ranges+at+n,s->ranges+at,(s->nranges-(at+n))*sizeof(*s->ranges)); s->nranges -= n; } SEQS *seqs_open(FOLDER *f) { const char *seqfile; char *t; SEQS *ss; FILE *sf; seqfile = profile_lookup(system_get_profile(),"seqfile"); if (seqfile == 0) seqfile = ".seq"; t = malloc(strlen(folder_path(f))+1+strlen(seqfile)+1); sprintf(t,"%s/%s",folder_path(f),seqfile); ss = malloc(sizeof(SEQS)); ss->f = f; ss->dirty = 0; ss->seqs = 0; ss->resvn = folder_must_remain_locked(f,"seqs_open"); ss->pathname = t; ss->fd = open(t,O_RDWR|O_CREAT,0600); if (ss->fd < 0) return(0); fcntl(ss->fd,F_SETFD,1); flock(ss->fd,LOCK_EX); lseek(ss->fd,0,SEEK_SET); sf = fdopen(dup(ss->fd),"r"); if (sf) { load_seqfile(sf,ss); fclose(sf); } return(ss); } static void seqs_flush(SEQS *ss) { FILE *f; if (ss->dirty) { if (any_nonempty_seqs(ss->seqs)) { lseek(ss->fd,0,SEEK_SET); f = fdopen(dup(ss->fd),"w"); if (f) { dump_seqfile(f,ss); ss->dirty = 0; fflush(f); ftruncate(fileno(f),lseek(fileno(f),0,SEEK_CUR)); fclose(f); } else { fprintf(stderr,"%s: can't write %s: %s\n",__progname,ss->pathname,strerror(errno)); } } else { if ((unlink(ss->pathname) < 0) && (errno != ENOENT)) { fprintf(stderr,"%s: can't remove %s: %s\n",__progname,ss->pathname,strerror(errno)); } else { ss->dirty = 0; } } } } void seqs_close(SEQS *ss) { seqs_flush(ss); seqs_abort(ss); } void seqs_abort(SEQS *ss) { SEQ *s; flock(ss->fd,LOCK_UN); close(ss->fd); free(deconst(ss->pathname)); folder_may_be_unlocked(ss->f,ss->resvn); while (ss->seqs) { s = ss->seqs; ss->seqs = s->link; free(deconst(s->name)); free(s->ranges); free(s); } free(ss); } SEQ *seq_lookup(SEQS *ss, const char *name) { SEQ *s; SEQ **sp; for (sp=&ss->seqs;(s=*sp);sp=&s->link) { if (!strcmp(s->name,name)) { *sp = s->link; s->link = ss->seqs; ss->seqs = s; return(s); } } s = malloc(sizeof(SEQ)); s->link = ss->seqs; ss->seqs = s; s->list = ss; s->name = strdup(name); s->size = 0; s->nranges = 0; s->ranges = 0; s->nalloc = 0; return(s); } void seq_remove(SEQ *s, int n) { seq_remove_range(s,n,n); } void seq_remove_all(SEQS *ss, int n) { SEQ *s; for (s=ss->seqs;s;s=s->link) seq_remove(s,n); } void seq_add(SEQ *s, int n) { seq_add_range(s,n,n); } void seq_remove_range(SEQ *s, int low, int high) { int i; int i0; for (i=0;(inranges)&&(s->ranges[i][1]= s->nranges) || (s->ranges[i][0] > high)) return; s->list->dirty = 1; if ((s->ranges[i][0] < low) && (s->ranges[i][1] > high)) { insert_range(s,i+1); s->ranges[i+1][0] = high + 1; s->ranges[i+1][1] = s->ranges[i][1]; s->ranges[i][1] = low - 1; s->size -= high + 1 - low; } else { if (s->ranges[i][0] < low) { s->size -= s->ranges[i][1] + 1 - low; s->ranges[i][1] = low - 1; i ++; } i0 = i; for (;(inranges)&&(s->ranges[i][1]<=high);i++) { s->size -= s->ranges[i][1] + 1 - s->ranges[i][0]; } if ((i < s->nranges) && (s->ranges[i][0] <= high)) { s->size -= high + 1 - s->ranges[i][0]; s->ranges[i][0] = high + 1; } if (i > i0) delete_ranges(s,i0,i-i0); } } void seq_add_range(SEQ *s, int low, int high) { int i; int i0; for (i=0;(inranges)&&(s->ranges[i][1]nranges) && (s->ranges[i][0] <= low) && (s->ranges[i][1] >= high) ) return; s->list->dirty = 1; if ((i >= s->nranges) || (s->ranges[i][0] > high+1)) { insert_range(s,i); s->ranges[i][0] = low; s->ranges[i][1] = high; s->size += high + 1 - low; return; } if (low < s->ranges[i][0]) { s->size += s->ranges[i][0] - low; s->ranges[i][0] = low; } i0 = i; for (i++;(inranges)&&(s->ranges[i][0]<=high+1);i++) { s->size += s->ranges[i][0] - s->ranges[i-1][1] - 1; } i --; if (s->ranges[i][1] > high) { high = s->ranges[i][1]; } else { s->size += high - s->ranges[i][1]; } s->ranges[i0][1] = high; if (i > i0) delete_ranges(s,i0+1,i-i0); } void seq_clear(SEQ *s) { if (s->nranges > 0) s->list->dirty = 1; s->size = 0; s->nranges = 0; } int seq_get(SEQ *s, int count, int off, int *vec) { int x; int m; int n; if (count < 1) return(s->size); for (x=0;xnranges;x++) { n = s->ranges[x][1] + 1 - s->ranges[x][0]; off -= n; if (off < 0) break; } if (x < s->nranges) { m = s->ranges[x][0] + off + n; while (count > 0) { if (m > s->ranges[x][1]) { x ++; if (x >= s->nranges) break; m = s->ranges[x][0]; } *vec++ = m++; count --; } } return(s->size); } int seq_test(SEQ *s, int n) { int i; for (i=0;(inranges)&&(s->ranges[i][1]nranges) && (s->ranges[i][0] <= n)); } int seqs_forall(SEQS *ss, void *cookie, int (*fn)(SEQ *, void *)) { SEQ *s; int rv; for (s=ss->seqs;s;s=s->link) { rv = (*fn)(s,cookie); if (rv) return(rv); } return(0); } #ifdef TESTBED int main(void); int main(void) { SEQ *s; char line[256]; char op; int n1; int n2; int i; s = malloc(sizeof(SEQ)); s->link = 0; s->list = 0; s->name = 0; s->nranges = 0; s->ranges = 0; s->nalloc = 0; while (1) { if (s->link) { int i; SEQ *s2; i = 0; for (s2=s->link;s2;s2=s2->link) i ++; printf("current[%d]:",i); } else { printf("current:"); } printf(" (%d)",s->size); for (i=0;inranges;i++) { if (s->ranges[i][0] == s->ranges[i][1]) { printf(" %d",s->ranges[i][0]); } else { printf(" %d-%d",s->ranges[i][0],s->ranges[i][1]); } } printf("\n"); noprint:; if (fgets(&line[0],sizeof(line),stdin) != &line[0]) goto out; /* break 2 */ if (line[0] == '#') goto noprint; if (line[0] == '"') { printf("%s",&line[0]); goto noprint; } switch (sscanf(&line[0]," %c%d%d",&op,&n1,&n2)) { case 1: switch (op) { case 'c': seq_clear(s); break; case '>': { SEQ *s2; s2 = malloc(sizeof(SEQ)); *s2 = *s; s2->link = s; s2->nalloc = s2->nranges + 8; s2->ranges = malloc(s2->nalloc*sizeof(*s2->ranges)); bcopy(s->ranges,s2->ranges,s->nranges*sizeof(*s->ranges)); s = s2; } break; case '<': { SEQ *s2; s2 = s->link; if (s2 == 0) { printf("stack empty\n"); } else { free(s->ranges); free(s); s = s2; } } break; default: goto err; break; } break; case 2: switch (op) { case '+': seq_add(s,n1); break; case '-': seq_remove(s,n1); break; default: goto err; break; } break; case 3: switch (op) { case '+': seq_add_range(s,n1,n2); break; case '-': seq_remove_range(s,n1,n2); break; case 'g': { int *v; int n; int p; v = malloc(n1*sizeof(int)); for (p=0;psize) abort(); p = n - n2; if (p < 0) p = 0; if (n1 < p) p = n1; printf("get: (%d)",p); for (n=0;n, <, c\n"); continue; break; } } out:; exit(0); } #endif