ftp.nice.ch/pub/next/connectivity/infosystems/Weather.1.1.s.tar.gz#/Weather-1.1-SRC/state.c

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.