/* looks.c by Michael Thorpe 2020-02-26 */ #include #include #include #include #include #include #include "runner.h" static struct look **looks=0; static int numlooks=0,pos=0; struct look *editlook=0; struct look *curlook=0; static unsigned char fraclook(struct look *me,int chan) { double val; val=me->subs[0]->func(me->subs[0],chan); val*=me->frac; if(val<0) val=0; if(255numsubs;i++) { c=me->subs[i]->func(me->subs[i],chan); if(valdmx->len) return(me->dmx->data[chan]); return(0); } static unsigned char proclook(struct look *me,int chan) { /* proclook should behave exactly the same code as storedlook, but needs to be a separate function */ return(storedlook(me,chan)); } static unsigned char blank(struct look *me,int chan) { return(0); } void nullupdate(struct look *me,double curtime) { int i; for(i=0;inumsubs;i++) me->subs[i]->update(me->subs[i],curtime); } /* returns look if it's defined, or NULL if not found */ struct look *findlook(const char *name) { int i,newloc; for(newloc=0;newlocname); if(i<0) /* this name comes after ours */ break; if(0==i) return(looks[newloc]); } return(0); } struct look *getlook(const char *name) { struct look *l; char *stmp,*ss,*se; int i,newloc; for(newloc=0;newlocname); if(i<0) /* this name comes after ours so newloc points to the right place */ break; if(0==i) return(looks[newloc]); } l=(struct look *)calloc(1,sizeof(struct look)); assert(l); l->name=strdup(name); assert(l->name); /* put the new look in place before populating because + looks that create alphabetically-earlier subs can screw us up */ looks=(struct look **)realloc(looks,(numlooks+1)*sizeof(struct look *)); assert(looks); if(newloc<=pos) pos++; if(newlocfunc=htp; stmp=strdup(l->name); assert(stmp); ss=stmp; while(1) { se=strchr(ss,'+'); if(se) *se='\0'; l->subs=(struct look **)realloc(l->subs,(l->numsubs+1)*sizeof(struct look *)); assert(l->subs); l->subs[l->numsubs++]=getlook(ss); if(!se) break; *se='+'; ss=se+1; } free(stmp); l->update=nullupdate; } else { l->func=blank; l->update=nullupdate; } return(l); } static void looks_store() { FILE *f; int i,j; f=fopen(".looks","w"); if(!f) { fputs("unable to save looks\n",stderr); return; } for(i=0;ifunc) { while(looks[i]->dmx->len && 0==looks[i]->dmx->data[looks[i]->dmx->len]) looks[i]->dmx->len--; if(!looks[i]->dmx->len) continue; fputs(looks[i]->name,f); for(j=1;j<=looks[i]->dmx->len;j++) fprintf(f,"\t%u",(unsigned int)looks[i]->dmx->data[j]); fputc('\n',f); } else if(fraclook==looks[i]->func) { fprintf(f,"%s\t=%f*%s\n",looks[i]->name,looks[i]->frac,looks[i]->subs[0]->name); } else if(proclook==looks[i]->func) { fprintf(f,"%s\t|%s\n",looks[i]->name,looks[i]->proc); } } if(fclose(f)) perror("close"); } int looks_load() { FILE *f,*procf; struct look *l,*l2; int i,line=0; unsigned long val; char *end; char buf[2500]; double dtmp; f=fopen(".looks","r"); if(!f) { if(ENOENT==errno) { goto NO_LOOKS; } perror("open(.looks)"); return(1); } while(fgets(buf,sizeof(buf),f)) { line++; end=strchr(buf,'\t'); if(!end) { fprintf(stderr,".looks:%d: Invalid name\n",line); return(1); } *end='\0'; l=getlook(buf); if(blank != l->func || l->dmx) { fprintf(stderr,".looks:%d: Look %s already defined\n",line,buf); return(1); } if('='==end[1]) { dtmp=strtod(end+2,&end); if('*' != end[0]) { fprintf(stderr,".looks:%d: Invalid fractional look\n",line); return(1); } end++; if(strchr(end,'\n')) *strchr(end,'\n')='\0'; l2=getlook(end); l->subs=(struct look **)malloc(1*sizeof(struct look *)); assert(l->subs); l->subs[0]=l2; l->numsubs=1; l->func=fraclook; l->frac=dtmp; } else if('|'==end[1]) { end+=2; if(strchr(end,'\n')) *strchr(end,'\n')='\0'; l->func=proclook; l->proc=strdup(end); assert(l->proc); procf=popen(end,"r"); /* popen really should allow "rb" */ if(!procf) { perror("popen"); return(1); } l->dmx=makeprocdmx(fileno(procf)); } else { l->func=storedlook; l->dmx=calloc(1,sizeof(struct dmx)); assert(l->dmx); l->dmx->data[0]=0; i=0; while(end[1]) { i++; val=strtoul(end+1,&end,10); if('\n' != *end && '\t' != *end) { fprintf(stderr,".looks:%d: Format error on channel %d\n",line,i); return(1); } if(255dmx->data[i]=val; } if(DMX_MAXCHANdmx->len=i; if(dmxout.lendmx->len) dmxout.len=l->dmx->len; } } if(fclose(f)) { perror("close"); return(1); } NO_LOOKS: if(!numlooks) /* If we didn't load any looks, set the curlook so we don't segfault from people asking for it. */ curlook=getlook(""); pos=0; atexit(looks_store); return(0); } void looks_redraw() { int first,i,j,k,l; char line[4096]; if(!looksframe.h || !looksframe.w) return; draw_titlebar(&looksframe); first=pos-(looksframe.h-1)/2; if(numlooksname); j+=strlen(looks[first+i]->name); do { line[j++]=' '; } while(j<8); if(htp==looks[first+i]->func) { memcpy(line+j,"HTP(",4); j+=4; for(k=0;knumsubs;k++) { if(k) line[j++]='+'; l=strlen(looks[first+i]->subs[k]->name); memcpy(line+j,looks[first+i]->subs[k]->name,l); j+=l; } line[j++]=')'; line[j]='\0'; } else if(blank==looks[first+i]->func) { j+=sprintf(line+j,"-"); } else if(storedlook==looks[first+i]->func) { j--; /* overwrite the last space written */ for(k=1;k<=looks[first+i]->dmx->len;k++) { switch(looks[first+i]->dmx->data[k]) { case 0: break; default: j+=sprintf(line+j," %d=%d",k,looks[first+i]->dmx->data[k]); break; case 255: j+=sprintf(line+j," %d=F",k); break; } } line[j]='\0'; } else if(fraclook==looks[first+i]->func) { sprintf(line+j,"=%f",looks[first+i]->frac); j+=strlen(line+j); while('0'==line[j-1]) j--; if('.'==line[j-1]) j--; sprintf(line+j,"*%s",looks[first+i]->subs[0]->name); j+=strlen(line+j); } else if(proclook==looks[first+i]->func) { sprintf(line+j,"|%s",looks[first+i]->proc); j+=strlen(line+j); } else { j+=sprintf(line+j,"???"); if(looks[first+i]->func) j+=sprintf(line+j," (%p)",looks[first+i]->func); } } assert(jfunc) { looks[pos]->func=storedlook; looks[pos]->dmx=calloc(1,sizeof(struct dmx)); assert(looks[pos]->dmx); looks[pos]->dmx->data[0]=0; } if(storedlook==looks[pos]->func) { editlook=looks[pos]; dmxin_setoffset(-1); looks_redraw(); } else { errmsg("Can't edit that look"); } return(1); case 18: /* Ctrl-R */ looks_redraw(); return(1); case KEY_UP: if(0