This is state.c in view mode; [Download] [Up]
/* * 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. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <libc.h> #include "util.h" #include "state.h" #include "StormFunc.h" #define MENU 1 SType lastType = Plain; static char *getStr(char *s, char *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; } static State * newMenu(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; } static State * newState(char *s) { State *S = Alloc(State); S->name = save(s); return S; } static String * addStr(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; } static void stripq(char *s) { if (*s == '\"'){ strcpy(s,s+1); if (s = rindex(s,'\"')) *s = '\0'; } } static void addMenu(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; } static void addString(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; static void readState(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(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; } /* static char *str(char *s) { return s? s : ""; } static void printState(State *s) { if (!s) { printf("huh?\n"); return; } printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label)); } */ void ReadState(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(char *s) { curState = state(s); if (strcmp(s,"Detach")==0) logout(); if (strcmp(s,"Ready")==0) fetchReports(); } static void execute(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); Case Pattern: break; Case Pause : break; } } void execState(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(char *s) { execState(curState,s); } int numItem(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; void setMenu(char *s) { curMenu = state(s); } MenuItem * curMenuItem(int n) { MenuItem *m; if (!curMenu) return (MenuItem *)0; for (m=curMenu->m; m && n-->0; m = m->next) ; return m; } static int valid(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(MenuItem *m) { return valid(m)? m->label : ""; } char *getSend(MenuItem *m) { return valid(m)? m->send : ""; } char *getGet(MenuItem *m) { return valid(m)? m->get : ""; } char *curMenuFirst(void) { return curMenu? curMenu->first : "**nada**"; } char *curMenuLast(void) { return curMenu? curMenu->last : "**nada**"; } char * getReport(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(char *label, char *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(char *label, char *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(); } /* void print(void){ int i; for (i=0;i<NS;i++) printState(ST[i]); } int main(main){ char s[1024]; ReadState("states"); print(); setState("Attach"); *s = '\0'; do { runState(s); } while (gets(s)); } */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.