/* This file is in the public domain. */ #include #include #include #include #include "util.h" #include "repo.h" #include "time.h" #include "ctype.h" #include "config.h" #include "structs.h" /* * Implementation of `repo' config-file sections. * * These are comparatively simple, with just three attributes (besides * the name on the `repo' line), each of which may must occur exactly * once. */ /* * Our private data. We have a bitmask of what fragments we have, plus * the REPO we're building and the CONFIG we're contemplating adding * it to. */ typedef struct sect_repo_priv SECT_REPO_PRIV; struct sect_repo_priv { unsigned int have; /* no HAVE_NAME; the name is on the repo line. */ #define SRP_HAVE_FILENAME 0x00000001 #define SRP_HAVE_TYPE 0x00000002 #define SRP_HAVE_GAP 0x00000004 REPO *r; CONFIG *cfg; } ; /* * Our start method. If the line is a repo line, pick out the name, * then set up the REPO and the SECT_REPO_PRIV. */ static void *sect_repo_start(const char *line, CONFIG *cfg) { int i; SECT_REPO_PRIV *p; int j; int k; i = 0; while (line[i] && UCisspace(line[i])) i ++; if (strncmp(line+i,"repo",4) || (line[i+4] && !UCisspace(line[i+4]))) return(0); i += 4; while (line[i] && UCisspace(line[i])) i ++; if (! line[i]) config_err(cfg,"missing repo name"); j = i; while (line[i] && !UCisspace(line[i])) i ++; k = i; while (line[i] && UCisspace(line[i])) i ++; if (line[i]) config_err(cfg,"space in repo name"); p = malloc(sizeof(SECT_REPO_PRIV)); p->have = 0; p->r = malloc(sizeof(REPO)); p->r->name = blk_to_nulterm(line+j,k-j); p->r->filename = 0; p->r->priv = 0; p->cfg = cfg; return(p); } /* * Our parse method. We handle everything inline here. The only thing * really noteworthy is the complex nested-function nesting used for * errors from timeintvl_parse; we need to do this because * timeintvl_parse can't take a pointer to config_err directly because * of the CONFIG * argument. */ static SPRV sect_repo_parse(void *pv, const char *line) { int i; int j; int k; SECT_REPO_PRIV *p; p = pv; i = 0; while (line[i] && UCisspace(line[i])) i ++; j = i; while (line[i] && !UCisspace(line[i])) i ++; k = i; while (line[i] && UCisspace(line[i])) i ++; if ((k-j == 4) && !bcmp(line+j,"file",4)) { if (p->have & SRP_HAVE_FILENAME) config_err(p->cfg,"extra `file' line in repo"); if (! line[i]) config_err(p->cfg,"missing filename on repo `file' line"); p->r->filename = strdup(line+i); p->have |= SRP_HAVE_FILENAME; return(SPRV_GOOD); } else if ((k-j == 4) && !bcmp(line+j,"type",4)) { if (p->have & SRP_HAVE_TYPE) config_err(p->cfg,"extra `type' line in repo"); if (! line[i]) config_err(p->cfg,"missing type on repo `type' line"); if (!strcmp(line+i,"int")) { p->r->type = DT_INT; } else if (!strcmp(line+i,"float")) { p->r->type = DT_FLOAT; } else { config_err(p->cfg,"bad type on repo `type' line"); } p->have |= SRP_HAVE_TYPE; return(SPRV_GOOD); } else if ((k-j == 3) && !bcmp(line+j,"gap",3)) { auto void err(const char *, ...) __attribute__((__format__(__printf__,1,2))); auto void err(const char *fmt, ...) { char *s; va_list ap; void free_s(void) { free(s); } va_start(ap,fmt); vasprintf(&s,fmt,ap); va_end(ap); config_err_post(&free_s,p->cfg,"%s",s); } if (p->have & SRP_HAVE_GAP) config_err(p->cfg,"extra `gap' line in repo"); if (! line[i]) config_err(p->cfg,"missing time interval on repo `gap' line"); p->r->maxgap = timeintvl_parse(line+i,&err); p->have |= SRP_HAVE_GAP; return(SPRV_GOOD); } else { return(SPRV_UNKNOWN); } } /* * Our done method. Check for missing pieces and either free the REPO * and error, if any, or link the REPO in to the CONFIG, if not. */ static void sect_repo_done(void *pv) { SECT_REPO_PRIV *p; const char *msg; p = pv; switch (p->have & (SRP_HAVE_FILENAME|SRP_HAVE_TYPE|SRP_HAVE_GAP)) { case 0: msg = "incomplete repo spec (no file, type, or gap lines)"; break; case SRP_HAVE_GAP: msg = "incomplete repo spec: no file or type lines)"; break; case SRP_HAVE_TYPE : msg = "incomplete repo spec (no file or gap lines)"; break; case SRP_HAVE_TYPE | SRP_HAVE_GAP: msg = "incomplete repo spec (no file line)"; break; case SRP_HAVE_FILENAME : msg = "incomplete repo spec (no type or gap lines)"; break; case SRP_HAVE_FILENAME | SRP_HAVE_GAP: msg = "incomplete repo spec (no type line)"; break; case SRP_HAVE_FILENAME | SRP_HAVE_TYPE : msg = "incomplete repo spec (no gap line)"; break; case SRP_HAVE_FILENAME | SRP_HAVE_TYPE | SRP_HAVE_GAP: msg = 0; break; } if (msg) { repo_free(p->r); } else { p->r->link = p->cfg->repos; p->cfg->repos = p->r; } free(p); if (msg) config_err(p->cfg,"%s",msg); } /* * Our SECT_OPS. */ const SECT_OPS sectops_repo = SECT_OPS_INIT(repo);