chiark / gitweb /
can display
authorian <ian>
Tue, 27 May 2008 23:35:25 +0000 (23:35 +0000)
committerian <ian>
Tue, 27 May 2008 23:35:25 +0000 (23:35 +0000)
hostside/gui-plan-testdata [new file with mode: 0644]
hostside/gui-plan.c

diff --git a/hostside/gui-plan-testdata b/hostside/gui-plan-testdata
new file mode 100644 (file)
index 0000000..2c72d4a
--- /dev/null
@@ -0,0 +1,12 @@
+train shinkansen has X7/P0. X5. X6. Q1. X8/P0.! X10* X12 Q2 A6/P0
+picio out on
+detect X8 1
+detect X6 1
+movpos A6 feat P 1 point
+movpos X2 feat R 0 relay
+movpos X7 feat P ? point
+movpos X7 gunk P 1 point
+movpos A5 feat P 2 point
+movpos Q0 feat Q 0 two
+movpos X8 feat Q 0 three
+picio out polarity <X2,X3,X4,Q3>
index 6306bb6e5da5c76225e28beb0f13cd19a04c1bc0..92e17aa606293e86264efc29923c262d221d631a 100644 (file)
 typedef int ErrorCode;
 
 #include "daemons.h"
+#include "dliste.h"
 #include "../layout/plan-data-format.h"
 
 #include <oop.h>
 #include <oop-read.h>
 
+#define NSEGMENTS (ui_plan_data.n_segments)
+
 typedef struct MaskState MaskState;
 struct MaskState {
   int x, y, width, height;
@@ -41,10 +44,16 @@ struct PosnState {
   MaskState edge;
 };
 
+typedef struct {
+  unsigned on:1, inv:1, det:1, trainown:2, updated_tmp:1;
+} SegFlags;
+
 typedef struct SegmovfeatState SegmovfeatState;
 struct SegmovfeatState {
   SegmovfeatState *next;
-  int invert, det, trainown, posn, redraw_needed;
+  SegFlags flags;
+  unsigned redraw_needed:1;
+  int posn;
   MaskState whole;
   PosnState (*posns)[2/*i*/][2/*det*/];
     /* posns[n_posns]=unknown if n_posns>1 */
@@ -53,9 +62,12 @@ struct SegmovfeatState {
 oop_source *events;
 const char *progname= "gui-plan";
 
+typedef struct TrainState TrainState;
+
 typedef struct {
   SegmovfeatState *mfs;
-  unsigned inverted:1, updated:1;
+  SegFlags flags; /* used by multiplexer client */
+  TrainState *owner;
 } SegState;
 
 static FILE *debug;
@@ -74,6 +86,8 @@ static size_t badcmdreport_recsz;
 void die_hook(void) { }
 void die_vprintf_hook(const char *fmt, va_list al) { }
 
+static void xlib_process(void);
+
 static void diex(const char *fn, const char *w) __attribute__((noreturn));
 static void diex(const char *fn, const char *w) {
   die("Xlib call failed: %s%s%s%s", fn,
@@ -99,65 +113,36 @@ static void diexpm(const char *fn, const char *w, int xpmst) {
       diexpm(#f, (w), xpmcall_xpmst);          \
   }while(0)
 
-int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
-  fprintf(stderr,"gui-plan: incorrect input: `%.*s': ",
-         (int)badcmdreport_recsz, badcmdreport_data);
-  vfprintf(stderr,fmt,al);
-  putc('\n',stderr);
-  exit(8);
-}
-
-static int lstrpdbsearch(const char *str, int l,
-                        const char *what,
-                        const void *items, int n_items,
-                        int itemsz) {
-  int min, maxe, try, cmp;
-  const void *try_item;
-  const char *try_name;
-  
-  min= 0;
-  maxe= n_items;
-  for (;;) {
-    if (min >= maxe) badcmd(0,"unknown %s `%.*s'",what,l,str);
-    try= min + (maxe - min) / 2;
-    try_item= (const char*)items + itemsz * try;
-    try_name= *(const char *const *)try_item;
-    cmp= lstrstrcmp(str, l, try_name ? try_name : "");
-    if (!cmp) return try;
-    if (cmp < 0) maxe= try;
-    else min= try + 1;
-  }
-}
-
 /*---------- input handling ----------*/
 
 typedef struct {
   const char *name;
   void (*on_eof)(void);
   void (*on_input_line)(ParseState *ps);
+  int (*on_badcmd)(void);
 } InputStream;
 
+static const InputStream *instream;
+
 static void *input_iferr(oop_source *evts, oop_read *stdin_read,
                          oop_rd_event evt, const char *errmsg, int errnoval,
-                         const char *data, size_t recsz, void *is_v) {
-  const InputStream *is= is_v;
+                         const char *data, size_t recsz, void *u_v) {
   const char *emsg;
   emsg= oop_rd_errmsg(stdin_read, evt, errnoval, OOP_RD_STYLE_GETLINE);
-  die("%s: %s", is->name, emsg);
+  die("%s: %s", instream->name, emsg);
 }
 
 static void *input_ifok(oop_source *evts, oop_read *cl_read,
                        oop_rd_event evt, const char *errmsg, int errnoval,
-                       const char *data, size_t recsz, void *is_v) {
-  const InputStream *is= is_v;
+                       const char *data, size_t recsz, void *u_v) {
   ParseState ps;
 
   if (evt == OOP_RD_EOF) {
-    is->on_eof();
+    instream->on_eof();
     abort();
   }
   if (evt != OOP_RD_OK) {
-    input_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,is_v);
+    input_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,0);
     return OOP_CONTINUE;
   }
 
@@ -165,8 +150,8 @@ static void *input_ifok(oop_source *evts, oop_read *cl_read,
   badcmdreport_recsz= recsz;
 
   ps.remain= data;
-  is->on_input_line(&ps);
-
+  instream->on_input_line(&ps);
+  xlib_process();
   return OOP_CONTINUE;
 }
 
@@ -176,6 +161,47 @@ static void *some_exception(oop_source *evts, int fd,
   die("poll exception on %s (fd %d)",name,fd);
 }
 
+int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
+  fprintf(stderr,"gui-plan: incorrect input: `%.*s': ",
+         (int)badcmdreport_recsz, badcmdreport_data);
+  vfprintf(stderr,fmt,al);
+  putc('\n',stderr);
+  return instream->on_badcmd();
+}
+
+static int lstrpdbsearch(const char *str, int l,
+                        const char *what,
+                        const void *items, int n_items,
+                        int itemsz) {
+  int min, maxe, try, cmp;
+  const void *try_item;
+  const char *try_name;
+  
+  min= 0;
+  maxe= n_items;
+  for (;;) {
+    if (min >= maxe) { badcmd(0,"unknown %s `%.*s'",what,l,str); return -1; }
+    try= min + (maxe - min) / 2;
+    try_item= (const char*)items + itemsz * try;
+    try_name= *(const char *const *)try_item;
+    cmp= lstrstrcmp(str, l, try_name ? try_name : "");
+    if (!cmp) return try;
+    if (cmp < 0) maxe= try;
+    else min= try + 1;
+  }
+}
+
+static int lstrpdbsearch_movfeat(const char *str, int l,
+                                const PlanSegmentData *sd) {
+  return lstrpdbsearch(str, l, "movfeat", sd->movfeats, sd->n_movfeats,
+                      sizeof(*sd->movfeats));
+}
+static int lstrpdbsearch_segment(const char *str, int l) {
+  return lstrpdbsearch(str, l, "segment",
+                      ui_plan_data.segments, ui_plan_data.n_segments,
+                      sizeof(*ui_plan_data.segments));
+}
+
 /*---------- drawing etc. ----------*/
 
 static int range_overlap(int x1, int width1, int x2, int width2) {
@@ -187,6 +213,12 @@ static int range_overlap(int x1, int width1, int x2, int width2) {
   return 1;
 }
 
+static void redraw_mark(SegmovfeatState *fs) {
+  if (fs->redraw_needed) return;
+  fs->redraw_needed= 1;
+  redraw_needed_count++;
+}
+
 static void xlib_expose(XExposeEvent *ev) {
   SegmovfeatState *fs;
   
@@ -196,14 +228,11 @@ static void xlib_expose(XExposeEvent *ev) {
   for (fs= states_head;
        fs;
        fs= fs->next) {
-    if (fs->redraw_needed)
-      continue;
     if (!range_overlap(fs->whole.x, fs->whole.width,
                       ev->x, ev->width)) continue;
     if (!range_overlap(fs->whole.y, fs->whole.height,
                       ev->y, ev->height)) continue;
-    fs->redraw_needed= 1;
-    redraw_needed_count++;
+    redraw_mark(fs);
   }
 }
 
@@ -221,15 +250,15 @@ static void redraw(SegmovfeatState *fs) {
          fs->whole.x, fs->whole.y,
          fs->whole.width, fs->whole.height,
          fs->whole.x, fs->whole.y) );
-  if (fs->invert >= 0) {
-    src= &fs->posns[fs->posn][fs->invert][fs->det];
+  if (fs->flags.on) {
+    src= &fs->posns[fs->posn][fs->flags.inv][fs->flags.det];
     XCALL( XCopyArea, "redraw",
           (d, src->pm, w, fs->whole.gc,
            0,0, src->width, src->height,
            src->x, src->y) );
   }
-  if (fs->trainown && src && src->edge.x >= 0) {
-    gcv.foreground= fs->trainown>1 ? train_pixel : owned_pixel;
+  if (fs->flags.trainown && src && src->edge.x >= 0) {
+    gcv.foreground= fs->flags.trainown>1 ? train_pixel : owned_pixel;
     XCALL( XChangeGC, "train/own",
           (d, src->edge.gc, GCForeground, &gcv) );
     XCALL( XFillRectangle, "train/own",
@@ -322,6 +351,7 @@ static void loadmask(MaskState *out, const PlanPixmapDataRef *ppd,
 /*---------- stdin input handling ----------*/
 
 static void stdin_eof(void) { exit(0); }
+static int stdin_badcmd(void) { exit(8); }
 
 static void stdin_input_line(ParseState *ps) {
   const char *slash, *movfeatname;
@@ -356,14 +386,10 @@ static void stdin_input_line(ParseState *ps) {
     movfeatname= 0;
     lmovfeatname= 0;
   }
-  segment_ix= lstrpdbsearch(ps->thisword, ps->lthisword,
-                           "segment", ui_plan_data.segments,
-                           ui_plan_data.n_segments, sizeof(*segment_d));
+  segment_ix= lstrpdbsearch_segment(ps->thisword,ps->lthisword);
   segment_d= &ui_plan_data.segments[segment_ix];
-  
-  movfeat_ix= lstrpdbsearch(movfeatname, lmovfeatname,
-                           "movfeat", segment_d->movfeats,
-                           segment_d->n_movfeats, sizeof(*movfeat_d));
+
+  movfeat_ix= lstrpdbsearch_movfeat(movfeatname, lmovfeatname, segment_d);
   movfeat_d= &segment_d->movfeats[movfeat_ix];
 
   if (ps->remain) {
@@ -380,16 +406,23 @@ static void stdin_input_line(ParseState *ps) {
   ps_neednoargs(ps);
 
   fs= &state[segment_ix].mfs[movfeat_ix];
-  fs->invert= invert;
-  fs->det= det;
-  fs->trainown= trainown;
+  if (invert>=0) {
+    fs->flags.on= 1;
+    fs->flags.inv= invert;
+  } else {
+    fs->flags.on= 0;
+    fs->flags.inv= 0;
+  }
+  fs->flags.det= det;
+  fs->flags.trainown= trainown;
   fs->posn= posn;
 
   redraw(fs);
-  xlib_process();
 }
 
-static const InputStream stdin_is= { "stdin", stdin_eof, stdin_input_line };
+static const InputStream stdin_is= {
+  "stdin", stdin_eof, stdin_input_line, stdin_badcmd
+};
 
 /*---------- multiplexer client ----------*/
 
@@ -454,26 +487,166 @@ static int sock_clientconnect(const char *node, const char *service) {
 }
 
 static void sock_eof(void) { die("EOF on multiplexer connection"); }
+static int sock_badcmd(void) { return -1; }
 
 /*---------- multiplexer protocol ----------*/
 
+struct TrainState {
+  struct { struct TrainState *next, *back; } others;
+  char *name;
+};
+
+static int poweron;
+static struct { TrainState *head, *tail; } trains;
+
+#define FOR_S for (s=0; s<NSEGMENTS; s++)
+
+static void mx_clear_updated(void) {
+  int s;
+  FOR_S
+    state[s].flags.updated_tmp= 0;
+}
+
+static void mx_redraw_feat(int s, int f) {
+  SegState *ss= &state[s];
+  SegmovfeatState *fs= &ss->mfs[f];
+  fs->flags= ss->flags;
+  fs->flags.on= poweron;
+  redraw_mark(fs);
+}
+
+static void mx_redraw_seg(int s) {
+  int f;
+  assert(!!state[s].flags.trainown == !!state[s].owner);
+  for (f=0; f < ui_plan_data.segments[s].n_movfeats; f++)
+    mx_redraw_feat(s,f);
+}
+
+static void mx_redraw_all(void) {
+  int s;
+  FOR_S
+    mx_redraw_seg(s);
+}
+
 static void si_detect(ParseState *ps) {
+  long dl;
+  int r, s;
+
+  r= ps_needword(ps);                                    if (r) return;
+  s= lstrpdbsearch_segment(ps->thisword,ps->lthisword);  if (s==-1) return;
+  r= ps_neednumber(ps,&dl,0,1,"detection flag");         if (r) return;
+  state[s].flags.det= dl;
+  mx_redraw_seg(s);
 }
 
 static void si_polarity(ParseState *ps) {
+  char *delim, *end;
+  int s;
+
+  mx_clear_updated();
+  if (*ps->remain++ != '<') { badcmd(ps,"missing <"); return; }
+
+  end= strchr(ps->remain,'>');
+  if (!end) { badcmd(ps,"missing >"); return; }
+
+  while (ps->remain < end) {
+    delim= memchr(ps->remain, ',', end - ps->remain);
+    if (!delim) delim= end;
+
+    ps->thisword= ps->remain;
+    ps->lthisword= delim - ps->remain;
+    ps->remain= delim+1;
+
+    s= lstrpdbsearch_segment(ps->thisword,ps->lthisword);   if (s<0) continue;
+    state[s].flags.updated_tmp= 1;
+  }
+  FOR_S {
+    if (state[s].flags.inv == state[s].flags.updated_tmp)
+      continue;
+    state[s].flags.inv= state[s].flags.updated_tmp;
+    mx_redraw_seg(s);
+  }
 }
 
 static void si_movpos(ParseState *ps) {
+  long pl;
+  int r,s,f, n_posns;
+  r= ps_needword(ps);                                    if (r) return;
+  s= lstrpdbsearch_segment(ps->thisword,ps->lthisword);  if (s<0) return;
+  r= ps_needword(ps);                                    if (r) return;
+  if (thiswordstrcmp(ps,"feat")) { badcmd(ps,"weird movpos"); return; }
+
+  r= ps_needword(ps);                                    if (r) return;
+  f= lstrpdbsearch_movfeat(ps->thisword, ps->lthisword,
+                          &ui_plan_data.segments[s]);   if (f<0) return;
+  
+  n_posns= ui_plan_data.segments[s].movfeats[f].n_posns;
+  if (ps->remain[0]=='?') goto unknown;
+  r= ps_neednumber(ps,&pl,0,n_posns-1,"movfeat posn");   if (r) goto unknown;
+  state[s].mfs[f].posn= pl;
+  mx_redraw_seg(s);
+  return;
+
+unknown:
+  state[s].mfs[f].posn= n_posns;
+  mx_redraw_seg(s);
 }
 
 static void si_on(ParseState *ps) {
+  poweron= 1;
+  mx_redraw_all();
 }
 
 static void si_off(ParseState *ps) {
+  poweron= 0;
+  mx_redraw_all();
 }
 
 static void si_train(ParseState *ps) {
-  
+  int r,sl,s;
+  int lastchar;
+  TrainState *train;
+  const char *seg;
+
+  mx_clear_updated();
+  r= ps_needword(ps); /* <train> */                if (r) return;
+
+  /* atomise the train name */
+  for (train=trains.head;
+       train;
+       train= train->others.next)
+    if (!thiswordstrcmp(ps,train->name))
+      goto found;
+  /* not found */
+  train= mmalloc(sizeof(*train));
+  train->name= mmalloc(ps->lthisword+1);
+  memcpy(train->name,ps->thisword,ps->lthisword);
+  train->name[ps->lthisword]= 0;
+  DLIST2_APPEND(trains,train,others);
+found:
+
+  r= ps_needword(ps);                              if (r) return;
+  if (thiswordstrcmp(ps,"has")) { badcmd(ps,"weird train"); return; }
+  while (ps_word(ps) >= 0) {
+    sl= strcspn(ps->thisword, "/.!*~#+");
+    if (sl > ps->lthisword) sl= ps->lthisword;
+    seg= ps->thisword;
+    if (*seg=='-') { seg++; sl--; }
+    s= lstrpdbsearch_segment(seg,sl);              if (s<0) continue;
+    lastchar= ps->thisword[ps->lthisword-1];
+    state[s].owner= train;
+    state[s].flags.updated_tmp= 1;
+    state[s].flags.trainown= 1 + (lastchar=='!' || lastchar=='*');
+  }
+  FOR_S {
+    if (state[s].flags.updated_tmp) {
+      mx_redraw_seg(s);
+    } else if (state[s].owner==train) {
+      state[s].owner= 0;
+      state[s].flags.trainown= 0;
+      mx_redraw_seg(s);
+    }
+  }
 }
 
 typedef struct MuxEventInfo MuxEventInfo;
@@ -507,14 +680,14 @@ static void si_connected(ParseState *ps) {
   sockprintf("\n");
 }
 
-static void si_problem(ParseState *ps) {
+static void si_fatal(ParseState *ps) {
   die("multiplexer reports problem: %.*s\n",
       (int)badcmdreport_recsz, badcmdreport_data);
 }
 static void si_ack(ParseState *ps) {
   ps_needword(ps); /* command */
   ps_needword(ps); /* status */
-  if (thiswordstrcmp(ps,"ok")) si_problem(0);
+  if (thiswordstrcmp(ps,"ok")) si_fatal(0);
 }
 
 static const MuxEventInfo muxeventinfos[]= {
@@ -530,9 +703,9 @@ static const MuxEventInfo muxeventinfos[]= {
 
   { "+executing", 0,            0             },
   { "+ack", 0,                  si_ack        },
-  { "+nak", 0,                  si_problem    },
-  { "=failed", 0,               si_problem    },
-  { "=denied", 0,               si_problem    },
+  { "+nak", 0,                  si_fatal      },
+  { "=failed", 0,               si_fatal      },
+  { "=denied", 0,               si_fatal      },
   { 0 }
 };
 
@@ -564,7 +737,8 @@ found:
 static const InputStream sock_is= {
   "multiplexer connection",
   sock_eof,
-  sock_input_line
+  sock_input_line,
+  sock_badcmd
 };
 
 /*---------- main program including much of the initialisation ----------*/
@@ -581,7 +755,6 @@ int main(int argc, const char *const *argv) {
   const PlanSegmentData *segment_d;
   const PlanSegmovfeatData *movfeat_d;
   char *ep;
-  const InputStream *instream;
   
   sys_events= oop_sys_new();  if (!sys_events) diee("oop_sys_new");
   events= oop_sys_source(sys_events);  assert(events);
@@ -642,19 +815,22 @@ int main(int argc, const char *const *argv) {
           &colour, &colour) );
   owned_pixel= colour.pixel;
 
-  state= mmalloc(sizeof(*state) * ui_plan_data.n_segments);
+  state= mmalloc(sizeof(*state) * NSEGMENTS);
   for (segment_ix= 0, segment_d= ui_plan_data.segments;
        segment_ix < ui_plan_data.n_segments;
        segment_ix++, segment_d++) {
+    state[segment_ix].flags.on= 0;
+    state[segment_ix].flags.inv= 0;
+    state[segment_ix].flags.det= 0;
+    state[segment_ix].flags.trainown= 0;
+    state[segment_ix].flags.updated_tmp= 0;
     state[segment_ix].mfs= fs=
       mmalloc(sizeof(*state[segment_ix].mfs) * segment_d->n_movfeats);
     for (movfeat_ix= 0, movfeat_d= segment_d->movfeats;
         movfeat_ix < segment_d->n_movfeats;
         movfeat_ix++, movfeat_d++, fs++) {
       fs->next= states_head;  states_head= fs;
-      fs->invert= -1;
-      fs->det= 0;
-      fs->trainown= 0;
+      fs->flags= state[segment_ix].flags;
       fs->posn= movfeat_d->n_posns;
       if (fs->posn==1) fs->posn= 0;
       fs->redraw_needed= 0;
@@ -707,8 +883,7 @@ int main(int argc, const char *const *argv) {
   if (!rd) diee("oop_rd_new_fd");
 
   oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
-                  input_ifok, (void*)instream,
-                  input_iferr, (void*)instream);
+                  input_ifok,0, input_iferr,0);
   if (oor) diee("oop_rd_read");
 
   events->on_fd(events, ConnectionNumber(d), OOP_READ,      xlib_readable,  0);