#include #include #include #include #include #include #include #include "profile.h" #include "wrap.h" #include "accum.h" #include "system.h" #include "deconst.h" typedef struct profent PROFENT; struct profent { PROFENT *link; const char *tag; const char *value; } ; struct mm_profile { PROFENT *ents; PROFENT **tail; unsigned int env : 1; } ; static PROFENT *new_profent(PROFILE *p, const char *tag, const char *val) { PROFENT *e; e = malloc(sizeof(PROFENT)); e->tag = strdup(tag); e->value = val ? strdup(val) : 0; e->link = 0; *p->tail = e; p->tail = &e->link; return(e); } PROFILE *profile_read(const char *fn) { int fd; PROFILE *profile; int e; if (fn == 0) { char *t; t = getenv("MM"); if (t) { fd = open(t,O_RDONLY,0); if (fd < 0) return(0); } else { const char *home; home = system_homedir(); t = malloc(strlen(home)+7); sprintf(t,"%s/.mmrc",home); fd = open(t,O_RDONLY,0); free(t); if (fd < 0) return(0); } } else { fd = open(fn,O_RDONLY,0); if (fd < 0) return(0); } profile = profile_read_fd(fd); e = errno; close(fd); errno = e; return(profile); } PROFILE *profile_read_fd(int fd) { int fd2; FILE *f; PROFILE *profile; int c; fd2 = dup(fd); if (fd2 < 0) return(0); f = fdopen(fd2,"r"); if (f == 0) { int e; e = errno; close(fd2); errno = e; return(0); } else { FILE *t; /* comment wrap before continue wrap, so comments don't break continues */ t = wrap_open_comment(f,1); if (t == 0) { int e; e = errno; fclose(f); errno = e; return(0); } f = t; t = wrap_open_continue(f,1); if (t == 0) { int e; e = errno; fclose(f); errno = e; return(0); } f = t; } profile = malloc(sizeof(PROFILE)); profile->ents = 0; profile->tail = &profile->ents; profile->env = 0; while (1) { ACCUM *tag; ACCUM *val; c = getc(f); if (c == EOF) break; tag = accum_init(ACCUM_NULLTERM); while ((c != EOF) && (c != '\n') && (c != ':')) { if (! isspace(c)) accum_char(tag,c); c = getc(f); } if (c == EOF) { accum_free(tag); break; } if (c == '\n') { new_profent(profile,accum_buf(tag),""); accum_free(tag); continue; } c = getc(f); val = accum_init(ACCUM_NULLTERM); while ((c != EOF) && (c != '\n')) { if (!isspace(c) || (accum_len(val) > 0)) accum_char(val,c); c = getc(f); } new_profent(profile,accum_buf(tag),accum_buf(val)); accum_free(tag); accum_free(val); if (c == EOF) break; } fclose(f); return(profile); } void profile_set_envoverride(PROFILE *p, int ovr) { p->env = (ovr != 0); } int profile_write_fd(PROFILE *p, int fd) { int fd2; FILE *f; PROFENT *e; fd2 = dup(fd); if (fd2 < 0) return(-1); f = fdopen(fd2,"w"); if (f == 0) { int e; e = errno; close(fd2); errno = e; return(-1); } for (e=p->ents;e;e=e->link) { if (e->value) { fprintf(f,"%s: %s\n",e->tag,e->value); /* what if error? */ } } if (fclose(f) == EOF) return(-1); return(0); } const char *profile_lookup(PROFILE *p, const char *tag) { PROFENT **ep; PROFENT *e; if (p == 0) return(0); if (p->env) { char *ev; char *v; int i; ev = malloc(7+strlen(tag)+1); bcopy("MMPROF_",ev,7); for (i=0;tag[i];i++) ev[i+7] = toupper(tag[i]); ev[i+7] = '\0'; v = getenv(ev); free(ev); if (v) return(v); } for (ep=&p->ents;(e=*ep);ep=&e->link) { if (!strcmp(e->tag,tag)) { *ep = e->link; if (p->tail == &e->link) p->tail = ep; e->link = p->ents; p->ents = e; return(e->value); } } new_profent(p,tag,0); return(0); } void profile_set(PROFILE *p, const char *tag, const char *val) { PROFENT **ep; PROFENT *e; for (ep=&p->ents;(e=*ep);ep=&e->link) { if (!strcmp(e->tag,tag)) { *ep = e->link; if (p->tail == &e->link) p->tail = ep; e->link = p->ents; p->ents = e; free(deconst(e->value)); e->value = val ? strdup(val) : 0; return; } } new_profent(p,tag,val); } const char *profile_relative_to(PROFILE *p, const char *tag, const char *def, const char *relto) { const char *s; s = profile_lookup(p,tag); if (! s) s = def; if (s[0] != '/') { char *t; t = malloc(strlen(relto)+1+strlen(s)+1); sprintf(t,"%s/%s",relto,s); s = t; } return(s); } void profile_free(PROFILE *p) { while (p->ents) { PROFENT *e; e = p->ents; p->ents = e->link; free(deconst(e->tag)); free(deconst(e->value)); free(e); } free(p); }