home *** CD-ROM | disk | FTP | other *** search
- /*
- * State machine and menu abstraction.
- * The idea is to keep as much of the hookup dialog
- * as possible in a text file, so that menus and hookup protocols
- * are easy to change here or in other apps.
- * It has grown a few warts.
- *
- * M. J. Hawley
- * mike@media-lab.mit.edu
- * Copyright (c) November 1991, MIT Media Laboratory.
- */
-
- #define MENU 1
- typedef enum { Plain, Pattern, Status, Goto, FlushS, Pause, CmdS } SType;
-
- typedef struct String {
- char *s;
- struct String *next;
- } String;
-
- typedef struct MenuItem {
- char *send, *get, *label;
- struct MenuItem *next;
- } MenuItem;
-
- typedef struct {
- int type;
- char *name;
- char *first, *last, *label;
- String *l;
- MenuItem *m;
- } State;
-
- #include "util.h"
-
- SType lastType = Plain;
-
- char *getStr(s,t) char *s, *t; {
- char end = ' ';
-
- *t = '\0';
- s = skipsp(s);
- lastType = Plain;
- switch (*s){
- Case '/': lastType = Pattern;
- Case '+': lastType = Status; s++;
- Case '!': lastType = CmdS; s++;
- Case ',': lastType = FlushS; s++;
- Case '=': lastType = Goto; s = skipsp(s+2);
- }
-
- if (*s=='/' || *s == '"') end = *s++;
- while (*s && !(*s == end || (end==' ' && *s == '\t'))){
- *t = *s++;
- if (*t == '\\') switch (*s){
- Case 'n': *t = '\n'; s++;
- Case 't': *t = '\t'; s++;
- Case 'b': *t = '\b'; s++;
- Default : *t = *s; s++;
- }
- t++;
- }
- *t = '\0';
- if (*s && *s != ' ' && *s != '\t') ++s;
- if (*s) s = skipsp(s);
- return s;
- }
-
- State *
- newMenu(s) char *s; {
- State *S = Alloc(State);
- char n[1024], first[1024], last[1024], label[1024];
- s = skipsp(skipsp(s)+4);
- sscanf(s,"%[^:]",n);
- s = skipsp(index(s,':')+1);
- s = getStr(s,first);
- s = getStr(s,last);
- s = getStr(s,label);
- S->name = save(n);
- S->label = save(label);
- S->first = save(first);
- S->last = save(last);
- S->type = MENU;
- return S;
- }
-
- State *
- newState(s) char *s; {
- State *S = Alloc(State);
- S->name = save(s);
- return S;
- }
-
- String *
- addStr(s,t) String *s; char *t; {
- String *start = s, *n = Alloc(String);
- char *p;
-
- p = n->s = save(t);
- if (*p=='/' && (p = index(p+1,'/'))){
- while (p[-1]=='\\') p = index(p+1,'/');
- if (p) *p = '\0';
- }
-
- if (!s) return n;
- while (s->next) s = s->next;
- s->next = n;
- return start;
- }
-
- stripq(s) char *s; {
- if (*s == '\"'){
- strcpy(s,s+1);
- if (s = rindex(s,'\"')) *s = '\0';
- }
- }
-
- void
- addMenu(S,s) State *S; char *s; {
- char send[1024], get[1024], label[1024];
- MenuItem *m = Alloc(MenuItem), *t;
- s = getStr(s,send); m->send = save(send);
- s = getStr(s,get); m->get = save(get);
- skipsp(s); strcpy(label,s); stripnl(label); stripq(label); m->label = save(label);
- for (t=S->m; t && t->next; t = t->next) ;
- if (t) t->next = m; else S->m = m;
- }
-
- void
- addString(S,s) State *S; char *s; {
- stripnl(s=skipsp(s));
- S->l = addStr(S->l,s);
- }
-
- #define MaxS 256
- static State *ST[MaxS];
- static int NS = 0;
-
- void
- readState(f) FILE *f; {
- char s[1024], n[1024];
- State *S = (State *)0;
- while (fgets(s,sizeof s,f)){
- stripcomment(s);
- if (blank(s)) continue;
- if (strncmp(s,"Menu",4)==0){
- S = newMenu(s);
- ST[NS++] = S;
- } else
- if (match(s,"[a-zA-Z]*:")){
- sscanf(s,"%[^:]",n);
- S = newState(n);
- ST[NS++] = S;
- } else
- if (S){
- if (S->type == MENU) addMenu(S,s); else
- addString(S,s);
- }
- }
- }
-
- State*
- state(s) char *s; {
- int i;
- s = skipsp(s);
- for (i=0;i<NS;i++)
- if (strcmp(s,ST[i]->name)==0) return ST[i];
- return (State *)0;
- }
-
- char *str(s) char *s; { return s? s : ""; }
-
- void
- printState(s) State *s; {
- if (!s) return printf("huh?\n");
- printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
- }
-
- void
- ReadState(s) char *s; {
- FILE *f;
- if (!NS){
- f = fopen(s,"r");
- if (f) readState(f), fclose(f);
- }
- setState("Attach");
- setMenu("Main");
- }
-
- State *curState = (State *)0;
-
- void
- setState(s) char *s; {
- curState = state(s);
- if (strcmp(s,"Detach")==0) logout();
- if (strcmp(s,"Ready")==0) fetchReports();
- }
-
- void
- execute(s) char *s; {
- char t[1024];
-
- if (s[0]=='/') s += strlen(s)+1;
- while ((s=getStr(s,t)) && *t) switch (lastType){
- Case CmdS: Command(t);
- Case Status : message(t);
- Case Plain : if (!state(t)) Put("%s",t);
- Case FlushS : Flush(t);
- Case Goto : setState(t);
- }
- }
-
- void
- execState(s,t) State *s; char *t; {
- String *l;
- if (!s) s = curState;
- if (!s || !s->l) return;
- for (l=s->l; l; l=l->next){
- if (l->s[0]!='/') execute(l->s);
- else
- if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
- }
- }
-
- void
- runState(s) char *s; {
- execState(curState,s);
- }
-
- int numItem(s) char *s; {
- int i = 0;
- State *S = state(s);
- MenuItem *m;
- if (!S) return 0;
- for (m=S->m; m; m=m->next) i++;
- return i;
- }
-
- State *curMenu;
-
- setMenu(s) char *s; { curMenu = state(s); }
-
- MenuItem *
- curMenuItem(n) int n; {
- MenuItem *m;
- if (!curMenu) return (MenuItem *)0;
- for (m=curMenu->m; m && n-->0; m = m->next) ;
- return m;
- }
-
- valid(m) MenuItem *m; {
- MenuItem *t;
- if (!curMenu) return 0;
- for (t=curMenu->m; t; t=t->next)
- if (t==m) return 1;
- return 0;
- }
-
-
- char *getLabel(m) MenuItem *m; { return valid(m)? m->label : ""; }
- char *getSend(m) MenuItem *m; { return valid(m)? m->send : ""; }
- char *getGet(m) MenuItem *m; { return valid(m)? m->get : ""; }
- char *curMenuFirst() { return curMenu? curMenu->first : "**nada**"; }
- char *curMenuLast() { return curMenu? curMenu->last : "**nada**"; }
-
- char *
- getReport(buf) char *buf; {
- char *p = buf+1;
- int starting = 1;
- strcpy(buf,"\n");
- while (pgets(p,1024) && !strindex(p,curMenuFirst())){
- if (Verbose) printf("+%s",p);
- if (starting && strlen(p)<=5)
- ;
- else
- if (strindex(p,"Enter 3-letter") || strindex(p,"Enter 2-letter")
- || strindex(p,"Selection:"))
- ;
- else
- if (strindex(p,"ress return") || strindex(p,"ress Return"))
- Put("\n");
- else
- starting = 0, p += strlen(p);
- }
- *p = '\0';
- if (curMenu) Flush(curMenuLast());
- return buf;
- }
-
- MenuItem *
- menuFor(label,name) char *label, *name; {
- int i;
- MenuItem *m;
- *name = '\0';
- for (i=0;i<NS;i++){
- if (ST[i]->type == MENU){
- for (m=ST[i]->m;m;m=m->next)
- if (strcmp(label,m->label)==0){
- strcpy(name,ST[i]->name);
- return m;
- }
- }
- }
- return (MenuItem *)0;
- }
-
- #define hackflush() sleep(1); while (pgets(hack,1024) && !strindex(hack,curMenuLast())) if (Verbose) printf("+%s",hack)
-
- void
- fetchReport(label,buf) char *label, *buf; {
- char menu[256];
- char hack[1024];
- MenuItem *m = menuFor(label,menu);
- *buf = '\0';
- if (!m) return;
-
- {
- State *s = state("Main");
- MenuItem *t = s->m;
- for (;t && strcmp(t->get,menu);t=t->next) ;
- if (t)
- Put("%s",t->send);
- }
- setMenu(menu); hackflush();
- Put("%s",m->send);
- if (strcmp(menu,"Main")==0) pgets(hack,1024);
- getReport(buf);
- if (strcmp(curMenu->name,"Main")){
- Put("m\n"), setMenu("Main");
- hackflush();
- } else
- hackflush();
- }
-
- /*
-
- print(){
- int i;
- for (i=0;i<NS;i++) printState(ST[i]);
- }
-
- main(){
- char s[1024];
- ReadState("states");
- print();
- setState("Attach");
- *s = '\0';
- do { runState(s); } while (gets(s));
- }
- */
-