/* This file is in the public domain. */ #include #include #include #include #include #include "structs.h" #include "repo.h" struct repo_cursor { REPO *r; off_t loc; TIMESTAMP start; TIMESTAMP stop; int eof; TIMESTAMP ts; char *lb; int la; int ll; int dataat; } ; struct repo_priv { FILE *f; struct stat stb; } ; REPO_PRIV *repo_open(const char *fn, void (*err)(const char *, ...)) { int fd; REPO_PRIV *p; fd = open(fn,O_RDWR,0666); if (fd < 0) (*err)("%s: %s",fn,strerror(errno)); p = malloc(sizeof(REPO_PRIV)); p->f = fdopen(fd,"r+"); fstat(fd,&p->stb); return(p); } int repo_same(REPO_PRIV *a, REPO_PRIV *b) { return( (a->stb.st_dev == b->stb.st_dev) && (a->stb.st_ino == b->stb.st_ino) ); } void repo_close(REPO_PRIV *p) { fclose(p->f); free(p); } void repo_free(REPO *r) { free(r->name); free(r->filename); repo_close(r->priv); free(r); } void repo_free_chain(REPO *chain) { REPO *r; while (chain) { r = chain; chain = r->link; repo_free(r); } } REPO *repo_lookup(LISTEN *l, const char *name, void (*err)(const char *, ...)) { MAP *m; int maxpri; int errpri; char *mapped; char *mstr; REPO *r; maxpri = -1; errpri = -1; for (m=l->mappings;m;m=m->link) { if (m->pri < maxpri) continue; switch ((*m->ops->match)(m->priv,name)) { case MATCH_NOMATCH: m->flags &= ~MF_MATCHED; break; case MATCH_MATCH: m->flags |= MF_MATCHED; maxpri = m->pri; break; case MATCH_ERROR: errpri = m->pri; break; default: abort(); break; } } if ((errpri >= 0) && (maxpri <= errpri)) { printf("error match\n"); // debugging (*err)("%s: bad repository name",name); } if (maxpri < 0) { printf("no matching mapping\n"); // debugging (*err)("%s: unmatched repository name",name); } mapped = 0; for (m=l->mappings;m;m=m->link) { if ((m->pri != maxpri) || !(m->flags & MF_MATCHED)) continue; mstr = (*m->ops->map)(m->priv,name); printf("mapped to %s\n",mstr); // debugging if (mapped && strcmp(mstr,mapped)) { printf("mapping conflict\n"); free(mapped); free(mstr); (*err)("%s: ambiguous repository name",name); } free(mapped); mapped = mstr; } if (! mapped) abort(); for (r=l->conf->repos;r;r=r->link) { if (! strcmp(mapped,r->name)) { printf("repo found\n"); // debugging return(r); } } printf("no repo found\n"); // debugging free(mapped); (*err)("%s: unknown repository name",name); abort(); } void repo_record(REPO *r, unsigned long long int ts, const char *data, void (*err)(const char *, ...)) { long long int iv; double dv; char *ep; char *ds; switch (r->type) { case DT_INT: iv = strtoll(data,&ep,0); if ((ep == data) || *ep) (*err)("invalid data"); asprintf(&ds,"%lld",iv); break; case DT_FLOAT: dv = strtod(data,&ep); if ((ep == data) || *ep) (*err)("invalid data"); asprintf(&ds,"%.20g",dv); break; default: abort(); break; } flock(fileno(r->priv->f),LOCK_EX); fseek(r->priv->f,0,SEEK_END); fprintf(r->priv->f,"%llu %s\n",ts,ds); fflush(r->priv->f); flock(fileno(r->priv->f),LOCK_UN); } REPO_CURSOR *repo_cursor_open(REPO *r, TIMESTAMP start, TIMESTAMP stop) { REPO_CURSOR *c; c = malloc(sizeof(REPO_CURSOR)); c->r = r; c->start = start; c->stop = stop; c->lb = 0; c->la = 0; return(c); } void repo_cursor_close(REPO_CURSOR *c) { free(c->lb); free(c); } void repo_cursor_rewind(REPO_CURSOR *c) { c->loc = 0; repo_cursor_advance(c); } int repo_cursor_eof(REPO_CURSOR *c) { return(c->eof); } TIMESTAMP repo_cursor_stamp(REPO_CURSOR *c) { return(c->ts); } const char *repo_cursor_data(REPO_CURSOR *c) { return(c->lb+c->dataat); } void repo_cursor_advance(REPO_CURSOR *c) { FILE *f; int ch; char *ep; f = c->r->priv->f; while (1) { fseeko(f,c->loc,SEEK_SET); c->ll = 0; while (1) { ch = getc(f); if (ch == EOF) { c->eof = 1; return; } if (c->ll >= c->la) c->lb = realloc(c->lb,c->la=c->ll+8); c->lb[c->ll++] = ch; if (ch == '\n') { c->lb[c->ll-1] = '\0'; c->ts = strtoull(c->lb,&ep,10); if ((c->ts >= c->start) && (c->ts < c->stop)) { while (*ep == ' ') ep ++; c->dataat = ep - c->lb; c->loc = ftello(f); return; } c->ll = 0; } } } }