chiark / gitweb /
gui-plan seems to work, yay
authorian <ian>
Sun, 19 Jun 2005 13:26:02 +0000 (13:26 +0000)
committerian <ian>
Sun, 19 Jun 2005 13:26:02 +0000 (13:26 +0000)
12 files changed:
hostside/.cvsignore
hostside/Makefile
hostside/__oop-read-copy.c [new file with mode: 0644]
hostside/client.c
hostside/gui-plan.c
hostside/parseutils.c [new file with mode: 0644]
hostside/serialio.c
hostside/trackloc.c [new file with mode: 0644]
hostside/utils.c
layout/Makefile
layout/plan-data-format.h
layout/plan-to-gui-data

index a45bb3545008b86ecddcfcd4116566ff9a949f30..889d7ba83da4871acc6c91e765866fecb84564ad 100644 (file)
@@ -6,3 +6,4 @@ layoutinfo.h
 *.d
 proto-expanded
 auproto-*
+gui-plan
index d988188613b7338055ed939da6d4b3105c683166..97a1a13f55c38d293165557d9d5d9d4fed5df858 100644 (file)
@@ -3,21 +3,26 @@
 include ../common.make
 include ../cprogs.make
 
-TARGETS=       hostside hostside-old
+TARGETS=       hostside hostside-old gui-plan
 
 all:           $(TARGETS)
 
-hostside-old:  serialio.o nmra.o main.o encode.o
+hostside-old:  serialio.o nmra.o main.o encode.o utils.o
                $(LINK)
 
-hostside:      hostside.o serialio.o client.o obc.o commands.o \
+hostside:      hostside.o serialio.o client.o obc.o commands.o utils.o \
                 nmra.o encode.o retransmit.o output.o auproto-pic.o \
+                parseutils.o \
                 -loop
                $(LINK)
 
 proto-expanded:        ../cebpic/README.protocol
                expand <$< $o
 
+gui-plan:      gui-plan.o utils.o parseutils.o ../layout/ui-plan-bot.o \
+                __oop-read-copy.o -loop
+               $(LINK) -L/usr/X11R6/lib -lXpm -lX11
+
 commands.o auproto-pic.o: auproto-pic.h
 
 auproto-%:     parse-proto-spec proto-expanded skelproto-%
@@ -28,7 +33,7 @@ layoutinfo.h: ../layout/ours.layout-data.c Makefile
 
 %.c:           layoutinfo.h
 
-safety:                safety.o utils.o ../layout/ours.layout-data.o
+safety:                safety.o utils.o trackloc.o ../layout/ours.layout-data.o
                $(LINK)
 
 clean:
diff --git a/hostside/__oop-read-copy.c b/hostside/__oop-read-copy.c
new file mode 100644 (file)
index 0000000..8cd5c67
--- /dev/null
@@ -0,0 +1,477 @@
+/* read.c, liboop, copyright 2000 Ian jackson
+   
+   This is free software; you can redistribute it and/or modify it under the
+   terms of the GNU Lesser General Public License, version 2.1 or later.
+   See the file COPYING for details. */
+
+#include "oop.h"
+#include "oop-read.h"
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+
+#undef MIN /* for systems that define it */
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+static void *on_time(oop_source*, struct timeval, void*);
+static void *on_readable(oop_source*, oop_readable*, void*);
+static void *on_process(oop_source*, oop_read*, int try_read);
+
+static int set_time_ifbuf(oop_source *oop, oop_read *rd);
+static void cancel_time(oop_source *oop, oop_read *rd);
+
+const oop_rd_style OOP_RD_STYLE_GETLINE[]= {{
+  OOP_RD_DELIM_STRIP,'\n', OOP_RD_NUL_FORBID, OOP_RD_SHORTREC_EOF,
+}};
+const oop_rd_style OOP_RD_STYLE_BLOCK[]= {{
+  OOP_RD_DELIM_NONE, 0,    OOP_RD_NUL_PERMIT, OOP_RD_SHORTREC_EOF,
+}};
+const oop_rd_style OOP_RD_STYLE_IMMED[]= {{
+  OOP_RD_DELIM_NONE, 0,    OOP_RD_NUL_PERMIT, OOP_RD_SHORTREC_SOONEST,
+}};
+
+struct oop_read {
+  /* set at creation time: */
+  oop_source *oop;
+  oop_readable *ra;
+  char *userbuf;
+  /* persistent state */
+  oop_rd_bufctl_op readahead; /* _ENABLE or _DISABLE */
+  char *allocbuf;
+  size_t alloc, used, discard;
+  size_t neednotcheck; /* data we've already searched for delimiter */
+  int displacedchar; /* >=0, first unused */
+  /* arguments to oop_rd_read */
+  oop_rd_style style;
+  size_t maxrecsz;
+  oop_rd_call *call_ok, *call_err;
+  void *data_ok, *data_err;
+};
+
+/* Buffer is structured like this if displacedchar>=0 and delim found:
+ *
+ *              done stuff,    displaced readahead - read     unused
+ *              we've called  delimiter| but not yet          buffer
+ *              back for              || returned             space
+ *              ddddddddddddddddddddddDOaaaaaaaaaaaaaaaaaaa____________
+ *              <------- discard ----->
+ *              <----------------------- used ------------>
+ *              <------------------------------------- alloc --------->
+ *
+ * If displacedchar>=0 then the the first character of readahead has
+ * been displaced by a nul byte and is stored in displacedchar.  If
+ * _DELIM_STRIP and the delimiter is found then the nul overwrites the
+ * delimiter.
+ *
+ *               Buffer when full   {this,max}                  may need
+ * DELIM found?  <-recval->      recdata  buffer required       readahead
+ *  NONE  n/a    ddddddddddOaaa_ recsz    recdata+1 == recsz+1  maxrecsz
+ *  KEEP  Yes    dddddddddDOaaa_ recsz    recdata+1 == recsz+1  maxrecsz
+ *  KEEP  No     ddddddddddOaaa_ recsz    recdata+1 == recsz+1  maxrecsz
+ *  STRIP Yes    dddddddddd0aaaa recsz+1  recdata   == recsz+1  maxrecsz+1
+ *  STRIP No     ddddddddddOaaaa recsz    recdata+1 == recsz+1  maxrecsz+1
+ *
+ * Key:  d = data to be returned
+ *       D = delimiter, being returned
+ *       a = readahead, not to be returned
+ *       O = readahead character displaced by a nul
+ *       0 = delimiter replaced by a nul
+ *       _ = unused
+ */
+
+static const char *const eventstrings_nl[]= {
+  "INTERNAL ERROR (_nl _OK) please report",
+  "End of file",
+  "Missing newline at end of file",
+  "Line too long",
+  "Nul byte",
+  "Nul byte, in line which is also too long",
+  "INTERNAL ERROR (_nl _SYSTEM) please report"
+};
+
+static const char *const eventstrings_other[]= {
+  "Record read successfully",
+  "End of file",
+  "Incomplete record at end of file",
+  "Record too long",
+  "Nul byte",
+  "Nul byte in record which is also too long",
+  "System error"
+};
+
+oop_read *oop_rd_new(oop_source *oop, oop_readable *ra, char *buf, size_t bufsz) {
+  oop_read *rd= 0;
+
+  assert(buf ? bufsz>=2 : !bufsz);
+
+  rd= oop_malloc(sizeof(*rd));  if (!rd) goto x_fail;
+  rd->oop= oop;
+  rd->ra= ra;
+  rd->userbuf= buf;
+  rd->readahead= OOP_RD_BUFCTL_ENABLE;
+  rd->allocbuf= 0;
+  rd->used= 0;
+  rd->alloc= buf ? bufsz : 0;
+  rd->discard= 0;
+  rd->neednotcheck= 0;
+  rd->displacedchar= -1;
+  rd->style= *OOP_RD_STYLE_IMMED;
+
+  return rd;
+
+x_fail:
+  oop_free(rd);
+  return 0;
+}
+
+static int set_time_ifbuf(oop_source *oop, oop_read *rd) {
+  if (rd->used > rd->discard)
+    return oop->on_time(oop,OOP_TIME_NOW,on_time,rd), 0; /* fixme */
+  return 0;
+}
+static void cancel_time(oop_source *oop, oop_read *rd) {
+  oop->cancel_time(oop,OOP_TIME_NOW,on_time,rd);
+}
+static int set_read(oop_source *oop, oop_read *rd) {
+  return rd->ra->on_readable(rd->ra,on_readable,rd), 0; /* fixme */
+}
+static void cancel_read(oop_source *oop, oop_read *rd) {
+  rd->ra->on_cancel(rd->ra);
+}
+
+int oop_rd_read(oop_read *rd, const oop_rd_style *style, size_t maxrecsz,
+               oop_rd_call *ifok, void *data_ok,
+               oop_rd_call *iferr, void *data_err) {
+  oop_source *oop= rd->oop;
+  int er;
+
+  cancel_time(oop,rd);
+  cancel_read(oop,rd);
+
+  if (style->delim_mode == OOP_RD_DELIM_NONE ||
+      rd->style.delim_mode == OOP_RD_DELIM_NONE ||
+      style->delim != rd->style.delim)
+    rd->neednotcheck= 0;
+
+  rd->style= *style;
+  rd->maxrecsz= maxrecsz;
+  rd->call_ok= ifok; rd->data_ok= data_ok;
+  rd->call_err= iferr; rd->data_err= data_err;
+
+  er= set_read(oop,rd);        if (er) return er;
+  er= set_time_ifbuf(oop,rd);  if (er) return er;
+  return 0;
+}
+
+void oop_rd_delete(oop_read *rd) {
+  rd->ra->on_cancel(rd->ra);
+  oop_free(rd->allocbuf);
+  oop_free(rd);
+}
+
+void oop_rd_cancel(oop_read *rd) {
+  cancel_time(rd->oop,rd);
+  cancel_read(rd->oop,rd);
+}
+
+const char *oop_rd_errmsg(oop_read *rd, oop_rd_event event, int errnoval,
+                         const oop_rd_style *style) {
+  if (event == OOP_RD_SYSTEM)
+    return strerror(errnoval);
+  else if (style && style->delim_mode != OOP_RD_DELIM_NONE
+          && style->delim == '\n')
+    return eventstrings_nl[event];
+  else
+    return eventstrings_other[event];
+}
+
+static void *on_readable(oop_source *oop, oop_readable *ra, void *rd_void) {
+  oop_read *rd= rd_void;
+
+  assert(oop == rd->oop);
+  assert(ra == rd->ra);
+  return on_process(oop,rd,1);
+}
+
+static void *on_time(oop_source *oop, struct timeval when, void *rd_void) {
+  oop_read *rd= rd_void;
+
+  assert(oop == rd->oop);
+  return on_process(oop,rd,0);
+}
+
+static size_t calc_dataspace(oop_read *rd) {
+  if (rd->style.delim_mode == OOP_RD_DELIM_STRIP) {
+    return rd->alloc;
+  } else {
+    return rd->alloc ? rd->alloc-1 : 0;
+  }
+}
+
+static void *on_process(oop_source *oop, oop_read *rd, int try_read) {
+  oop_rd_event event;
+  int evkind; /* 0=none, -1=error, 1=something */
+  int errnoval, nread, cancelnow;
+  oop_rd_call *call;
+  char *buf, *delimp;
+  const char *errmsg;
+  size_t maxrecsz; /* like in arg to oop_rd_read, but 0 -> large val */
+  size_t maxbufreqd; /* maximum buffer we might possibly want to alloc */
+  size_t readahead; /* max amount of data we might want to readahead */
+  size_t want; /* amount we want to allocate or data we want to read */
+  size_t dataspace; /* amount of buffer we can usefully fill with data */
+  size_t thisrecsz; /* length of the record we've found */
+  size_t thisrecdata; /* length of data representing the record */
+  void *call_data;
+
+  cancel_time(oop,rd);
+
+  if (rd->userbuf) {
+    buf= rd->userbuf;
+  } else {
+    buf= rd->allocbuf;
+  }
+  
+  if (rd->discard) {
+    rd->used -= rd->discard;
+    rd->neednotcheck -= rd->discard;
+    memmove(buf, buf + rd->discard, rd->used);
+    rd->discard= 0;
+  }
+  if (rd->displacedchar >= 0) {
+    assert(rd->used > 0);
+    buf[0]= rd->displacedchar;
+    rd->displacedchar= -1;
+  }
+
+  maxrecsz= rd->maxrecsz ? rd->maxrecsz : INT_MAX / 5 /* allows +20 and *4 */;
+  maxbufreqd= maxrecsz+1;
+
+  if (rd->userbuf && maxbufreqd > rd->alloc) {
+    maxrecsz -= (maxbufreqd - rd->alloc);
+    maxbufreqd= rd->alloc;
+  }
+
+  if (rd->style.delim_mode == OOP_RD_DELIM_STRIP) {
+    readahead= maxrecsz+1;
+  } else {
+    readahead= maxrecsz;
+  }
+
+  for (;;) {
+    evkind= 0;
+    event= -1;
+    thisrecdata= thisrecsz= 0;
+    errnoval= 0;
+
+    assert(rd->used <= rd->alloc);
+    dataspace= calc_dataspace(rd);
+    
+    if (/* delimiter already in buffer, within max record data ? */
+       rd->style.delim_mode != OOP_RD_DELIM_NONE &&
+       (delimp= memchr(buf + rd->neednotcheck, rd->style.delim,
+                       MIN(rd->used, readahead) - rd->neednotcheck))) {
+      
+      thisrecsz= (delimp - buf);
+      thisrecdata= thisrecsz+1;
+      if (rd->style.delim_mode == OOP_RD_DELIM_KEEP)
+       thisrecsz= thisrecdata;
+      event= OOP_RD_OK;
+      evkind= +1;
+
+    } else if (rd->used >= readahead) {
+      
+      thisrecsz= thisrecdata= maxrecsz;
+      evkind= +1;
+
+      if (rd->style.delim_mode == OOP_RD_DELIM_NONE) {
+       event= OOP_RD_OK;
+      } else {
+       event= OOP_RD_LONG;
+       if (rd->style.shortrec_mode < OOP_RD_SHORTREC_LONG) {
+         evkind= -1;
+         thisrecsz= thisrecdata= 0;
+       }
+      }
+
+    } else if (/* want to return ASAP, and we have something ? */
+              rd->style.shortrec_mode == OOP_RD_SHORTREC_SOONEST &&
+              rd->used > 0 && rd->alloc >= 2) {
+      
+      thisrecdata= rd->used;
+      if (thisrecdata == rd->alloc) thisrecdata--;
+      thisrecsz= thisrecdata;
+      event= OOP_RD_OK;
+      evkind= +1;
+
+    }
+
+    want= 0;
+    if (evkind && thisrecdata && thisrecsz >= rd->alloc) {
+      /* Need to make space for the trailing nul */
+      want= rd->alloc+1;
+    } else if (!evkind && !rd->userbuf &&
+              rd->used >= dataspace && rd->alloc < maxbufreqd) {
+      /* Need to make space to read more data */
+      want= rd->alloc + 20;
+      want <<= 2;
+      want= MIN(want, maxbufreqd);
+    }
+
+    if (want) {
+      assert(!rd->userbuf);
+      assert(want <= maxbufreqd);
+
+      buf= oop_realloc(rd->allocbuf,want);
+      if (!buf) {
+       event= OOP_RD_SYSTEM;
+       evkind= -1;
+       errnoval= ENOMEM;
+       thisrecsz= thisrecdata= 0;
+       break;
+      }
+      rd->allocbuf= buf;
+      rd->alloc= want;
+    }
+
+    if (evkind) break; /* OK, process it then */
+
+    if (!try_read) return OOP_CONTINUE; /* But we weren't told it was ready. */
+
+    dataspace= calc_dataspace(rd);
+    want= MIN(dataspace, readahead);
+    assert(rd->used < want);
+
+    errno= 0;
+    nread= rd->ra->try_read(rd->ra, buf+rd->used, want-rd->used);
+    if (errno == EAGAIN) return OOP_CONTINUE;
+
+    if (nread > 0) {
+      rd->neednotcheck= rd->used;
+      rd->used += nread;
+      continue;
+    }
+
+    if (nread < 0) { /* read error */
+
+      event= OOP_RD_SYSTEM;
+      evkind= -1;
+      errnoval= errno;
+      thisrecsz= thisrecdata= rd->used;
+      break;
+
+    } else {
+
+      if (rd->used) {
+       event= OOP_RD_PARTREC;
+       evkind= (rd->style.shortrec_mode == OOP_RD_SHORTREC_FORBID) ? -1 : +1;
+       thisrecsz= thisrecdata= rd->used;
+      } else {
+       event= OOP_RD_EOF;
+       evkind= +1;
+      }
+      break;
+
+    }
+  }
+
+  /* OK, we have an event of some kind */
+
+  /* Nul byte handling */
+  if (thisrecsz > 0 && rd->style.nul_mode != OOP_RD_NUL_PERMIT) {
+    size_t checked;
+    char *nul, *notnul;
+    
+    for (checked=0;
+        (nul= memchr(buf+checked,0,thisrecsz-checked));
+        ) {
+      if (rd->style.nul_mode == OOP_RD_NUL_FORBID) {
+       event= OOP_RD_NUL;
+       evkind= -1;
+       thisrecdata= thisrecsz= 0;
+       break;
+      }
+      assert(rd->style.nul_mode == OOP_RD_NUL_DISCARD);
+      for (notnul= nul+1;
+          notnul < buf+thisrecsz && notnul == '\0';
+          notnul++);
+      thisrecsz-= (notnul-nul);
+      checked= nul-buf;
+      memmove(nul,notnul,thisrecsz-checked);
+    }
+  }
+
+  /* Checks that all is well */
+
+  assert(evkind);
+  assert(thisrecsz <= thisrecdata);
+  assert(!rd->maxrecsz || thisrecsz <= rd->maxrecsz);
+  assert(thisrecdata <= rd->used);
+
+  rd->discard= thisrecdata;
+
+  cancelnow= (evkind < 0) || (event == OOP_RD_EOF);
+
+  if (!cancelnow) {
+    errnoval= set_time_ifbuf(oop,rd);
+    if (errnoval) {
+      event= OOP_RD_SYSTEM;
+      evkind= -1;
+      cancelnow= 1;
+      thisrecsz= thisrecdata= 0;
+      rd->discard= 0;
+    }
+  }
+
+  if (evkind < 0) {
+    call= rd->call_err;
+    call_data= rd->data_err;
+    errmsg= oop_rd_errmsg(rd,event,errnoval,&rd->style);
+  } else {
+    call= rd->call_ok;
+    call_data= rd->data_ok;
+    errmsg= 0;
+  }
+
+  if (thisrecdata) {
+    /* We have to fill in a nul byte. */
+    assert(thisrecsz < rd->alloc);
+    if (thisrecsz == thisrecdata && thisrecsz < rd->used)
+      rd->displacedchar= (unsigned char)buf[thisrecdata];
+    buf[thisrecsz]= 0;
+  }
+
+  if (cancelnow)
+    oop_rd_cancel(rd);
+
+  return
+    call(oop,rd, event,errmsg,errnoval,
+        (thisrecdata ? buf : 0), thisrecsz, call_data);
+}
+
+oop_read *oop_rd_new_fd(oop_source *oop, int fd, char *buf, size_t bufsz) {
+  oop_readable *ra;
+  oop_read *rd;
+
+  ra= oop_readable_fd(oop,fd);
+  if (!ra) return 0;
+
+  rd= oop_rd_new(oop,ra,buf,bufsz);
+  if (!rd) { ra->delete_tidy(ra); return 0; }
+
+  return rd;
+}
+
+int oop_rd_delete_tidy(oop_read *rd) {
+  oop_readable *ra= rd->ra;
+  oop_rd_delete(rd);
+  return ra->delete_tidy(ra);
+}
+
+void oop_rd_delete_kill(oop_read *rd) {
+  oop_readable *ra= rd->ra;
+  oop_rd_delete(rd);
+  ra->delete_kill(ra);
+}  
index 22784ed25b94bce2eb23018a3fbb3373cb18fc1f..e3625ba511bdee2de7f4efbadc1ca15580ddf420 100644 (file)
@@ -16,98 +16,6 @@ void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
   owrite(&ps->cl->ch,"\n",1);
 }
 
-void badcmd(ParseState *ps, const char *fmt, ...) {
-  va_list al;
-  va_start(al,fmt);
-  vbadcmd(ps,fmt,al);
-  va_end(al);
-}
-
-int ps_word(ParseState *ps) {
-  const char *space;
-  if (!ps->remain) return 0;
-  space= strchr(ps->remain, ' ');
-  ps->thisword= ps->remain;
-  if (space) {
-    ps->lthisword= space - ps->thisword;
-    ps->remain= space + 1;
-  } else {
-    ps->lthisword= strlen(ps->remain);
-    ps->remain= 0;
-  }
-  return 1;
-}
-
-int ps_needword(ParseState *ps) {
-  if (!ps_word(ps)) { badcmd(ps,"too few args"); return 0; }
-  return 1;
-}
-
-int ps_neednumber(ParseState *ps, long *r, long mi, long mx, const char *wh) {
-  char *ep;
-  long v;
-  
-  if (!ps_needword(ps)) return 0;
-  errno= 0; v= strtol(ps->thisword,&ep,0);
-  if (errno || ep != ps->thisword + ps->lthisword) {
-    badcmd(ps,"invalid number for %s",wh);
-    return 0;
-  }
-  if (v < mi || v > mx) {
-    badcmd(ps,"%s %ld out of range %ld..%ld",wh,v,mi,mx);
-    return 0;
-  }
-  *r= v;
-  return 1;
-}
-
-int ps_neednoargs(ParseState *ps) {
-  if (ps->remain) {
-    badcmd(ps,"too many arguments");
-    return 0;
-  }
-  return 1;
-}
-int ps_needhextoend(ParseState *ps, Byte *d, int *remain_io) {
-  Byte *d_end;
-  char buf[3], *ep;
-
-  d_end= d + *remain_io;
-  buf[2]= 0;
-  
-  if (!ps->remain) { badcmd(ps,"need hex data block"); return 0; }
-  for (;;) {
-    if (!ps_word(ps)) return 0;
-    while (ps->lthisword > 0) {
-      if (ps->lthisword & 1) {
-       badcmd(ps,"hex data block with odd number of digits in part");
-       return 0;
-      }
-      buf[0]= ps->thisword[0];
-      buf[1]= ps->thisword[1];
-      if (d >= d_end) { badcmd(ps,"hex data block too long"); return 0; }
-      *d++= strtoul(buf,&ep,16);
-      if (*ep) { badcmd(ps,"invalid digit in hex data block"); return 0; }
-      ps->lthisword -= 2;
-      ps->thisword += 2;
-    }
-  }
-
-  *remain_io= d_end - d;
-  return 1;
-}
-
-int lstrstrcmp(const char *a, int la, const char *b) {
-  int lb= strlen(b);
-  if (la != lb) return 1;
-  return memcmp(a,b,la);
-}
-
-int thiswordstrcmp(ParseState *ps, const char *b) {
-  return lstrstrcmp(ps->thisword, ps->lthisword, b);
-}
-
 const void *any_lookup(ParseState *ps, const void *inf, size_t sz) {
   const char *tname;
   
index 42140edc2f177b5c362bd05621e1e14b46183ca7..55fb48a7877fe8b7cca361d23412d81518e643f1 100644 (file)
 /*
- * usage: gui-plan <windowid>
+ * usage: .../gui-plan [<windowid>]
  * protocol on stdin:
- *  series of uint32_t's in network byte order
- *   top byte is opcode
- *          0x00  off
- *          0x01  on
- *          0x01  detect
- *   next byte is movposcomb
- *   remaining bytes are segment number
+ *  series of lines
+ *   off <segname>[/[<movfeat>]
+ *   [i]on <segname>[[/<movfeat>] <movpos>]
+ *   [i]det <segname>[[/<movfeat>] <movpos>]
  */
 
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <X11/Xlib.h>
+#include <X11/xpm.h>
+
+#include "hostside.h"
+#include "../layout/plan-data-format.h"
+
+#include <oop.h>
+#include <oop-read.h>
+
+typedef struct SegmovfeatState SegmovfeatState;
+struct SegmovfeatState {
+  SegmovfeatState *next;
+  int invert, det, posn, x, y, width, height, redraw_needed;
+  GC gc;
+  Pixmap (*posns)[2/*i*/][2/*det*/];
+};
+
+oop_source *events;
+
+static SegmovfeatState **state, *states_head;
+static Display *d;
+static oop_source_sys *sys_events;
+static Window w;
+static int redraw_needed_count, expose_count;
+
+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,
+      (w)?" (":"", (w), (w)?")":"");
+}
+
+#define XCALL(f,w,al) do{                      \
+    if (!( (f) al ))                           \
+      diex(#f, (w));                           \
+  }while(0)
+
+static void diexpm(const char *fn, const char *w, int xpmst)
+     __attribute__((noreturn));
+static void diexpm(const char *fn, const char *w, int xpmst) {
+  die("Xpm call failed: %s%s%s%s: %s", fn,
+      (w)?" (":"", (w), (w)?")":"", XpmGetErrorString(xpmst));
+}
+
+#define XPMCALL(f,w,al) do{                    \
+    int xpmcall_xpmst;                         \
+    xpmcall_xpmst= ((f) al);                   \
+    if (xpmcall_xpmst != XpmSuccess)           \
+      diexpm(#f, (w), xpmcall_xpmst);          \
+  }while(0)
+
+void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
+  fprintf(stderr,"gui-plan: incorrect input: ");
+  vfprintf(stderr,fmt,al);
+  putc('\n',stderr);
+  exit(8);
+}
+
+static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
+                         oop_rd_event evt, const char *errmsg, int errnoval,
+                         const char *data, size_t recsz, void *cl_v) {
+  die("read stdin: %s", oop_rd_errmsg(stdin_read, evt,
+                                     errnoval, OOP_RD_STYLE_GETLINE));
+  return OOP_CONTINUE;
+}
+
+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",what);
+    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 void *some_exception(oop_source *evts, int fd,
+                           oop_event evt, void *cl_v) {
+  die("poll exception on fd %d",fd);
+}
+
+static int range_overlap(int x1, int width1, int x2, int width2) {
+  /* works for y's and heights too, obviously. */
+  int rhs1, rhs2;
+  rhs1= x1 + width1;
+  rhs2= x2 + width2;
+  if (rhs1 <= x2 || rhs2 <= x1) return 0;
+  return 1;
+}
+
+static void xlib_expose(XExposeEvent *ev) {
+  SegmovfeatState *fs;
+  
+  expose_count= ev->count;
+  if (!ev->width || !ev->height) return;
+
+  for (fs= states_head;
+       fs;
+       fs= fs->next) {
+    if (fs->redraw_needed)
+      continue;
+    if (!range_overlap(fs->x, fs->width,
+                      ev->x, ev->width)) continue;
+    if (!range_overlap(fs->y, fs->height,
+                      ev->y, ev->height)) continue;
+    fs->redraw_needed= 1;
+    redraw_needed_count++;
+  }
+}
+
+static void redraw(SegmovfeatState *fs) {
+  Pixmap src;
+  
+  if (fs->redraw_needed) {
+    fs->redraw_needed= 0;
+    redraw_needed_count--;
+  }
+  if (fs->invert < 0) {
+    XCALL( XFillRectangle, "redraw",
+          (d,w, fs->gc,
+           fs->x, fs->y,
+           fs->width, fs->height) );
+  } else {
+    src= fs->posns[fs->posn][fs->invert][fs->det];
+    XCALL( XCopyArea, "redraw",
+          (d, src, w, fs->gc,
+           0,0, fs->width, fs->height,
+           fs->x, fs->y) );
+  }
+}
+
+static void redraw_as_needed(void) {
+  SegmovfeatState *fs;
+
+  for (fs= states_head;
+       fs;
+       fs= fs->next)
+    if (fs->redraw_needed)
+      redraw(fs);
+  assert(!redraw_needed_count);
+}
+  
+static Bool evpredicate_always(Display *d, XEvent *ev, XPointer a) {
+  return True;
+}
+
+static void xlib_process(void) {
+  XEvent ev;
+  Status xst;
+  
+  for (;;) {
+    xst= XCheckIfEvent(d,&ev,evpredicate_always,0);
+    if (!xst) {
+      if (!redraw_needed_count || expose_count)
+       return;
+      redraw_as_needed();
+      continue;
+    }
+
+    switch (ev.type) {
+    case Expose: xlib_expose(&ev.xexpose); break;
+    case NoExpose: break;
+    default: die("unrequested event type %d\n",ev.type);
+    }
+  }
+}
+
+static void *xlib_readable(oop_source *evts, int fd,
+                          oop_event evt, void *cl_v) {
+  xlib_process();
+  return OOP_CONTINUE;
+}
+                          
+static void *stdin_ifok(oop_source *evts, oop_read *cl_read,
+                       oop_rd_event evt, const char *errmsg, int errnoval,
+                       const char *data, size_t recsz, void *cl_v) {
+  const char *slash, *movfeatname;
+  ParseState ps;
+  int invert, det, segment_ix, movfeat_ix, lmovfeatname;
+  long posn;
+  const PlanSegmentData *segment_d;
+  const PlanSegmovfeatData *movfeat_d;
+  SegmovfeatState *fs;
+
+  if (evt == OOP_RD_EOF)
+    exit(0);
+  
+  if (evt != OOP_RD_OK)
+    return stdin_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cl_v);
+
+  ps.cl= 0;
+  ps.remain= data;
+  ps_needword(&ps);
+
+  if (!thiswordstrcmp(&ps,"off")) {
+    invert= -1;
+    det= 0;
+  } else {
+    invert= (ps.thisword[0]=='i');
+    if (invert) { ps.thisword++; ps.lthisword--; }
+    det= (!thiswordstrcmp(&ps,"on") ? 0 :
+         !thiswordstrcmp(&ps,"det") ? 1 :
+         (badcmd(&ps,"unknown command"),-1));
+  }
+  ps_needword(&ps);
+  slash= memchr(ps.thisword, '/', ps.lthisword);
+  if (slash) {
+    movfeatname= slash + 1;
+    lmovfeatname= (ps.thisword + ps.lthisword) - movfeatname;
+    ps.lthisword= slash - ps.thisword;
+  } else {
+    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_d= &ui_plan_data.segments[segment_ix];
+  
+  movfeat_ix= lstrpdbsearch(movfeatname, lmovfeatname,
+                           "movfeat", segment_d->movfeats,
+                           segment_d->n_movfeats, sizeof(*movfeat_d));
+  movfeat_d= &segment_d->movfeats[movfeat_ix];
+
+  if (ps.remain) {
+    if (invert<0) badcmd(0,"off may not take movfeatpos");
+    ps_neednumber(&ps, &posn, 0, movfeat_d->n_posns-1, "movfeatpos");
+  } else {
+    if (invert>=0 && movfeat_d->n_posns > 1) badcmd(0,"movfeatpos needed");
+    posn= 0;
+  }
+
+  ps_neednoargs(&ps);
+
+  fs= &state[segment_ix][movfeat_ix];
+  fs->invert= invert;
+  fs->det= det;
+  fs->posn= posn;
+
+  redraw(fs);
+  xlib_process();
+
+  return OOP_CONTINUE;
+}
+
+int main(int argc, const char *const *argv) {
+  static XpmColorSymbol coloursymbols[2]= {
+    { (char*)"space", 0, 0 },
+    { (char*)"mark",  0, 1 }
+  };
+  
+  oop_read *rd;
+  const char *arg;
+  Pixmap bg_pixmap;
+  Pixmap mask;
+  XpmAttributes mattribs;
+  XWindowAttributes wattribs;
+  XColor background_colour;
+  int segment_ix, movfeat_ix, posn, invert, det, oor;
+  SegmovfeatState *fs;
+  const PlanSegmentData *segment_d;
+  const PlanSegmovfeatData *movfeat_d;
+  XGCValues gcv;
+
+  d= XOpenDisplay(0);  if (!d) die("XOpenDisplay failed");
+
+  if ((arg= *++argv)) {
+    char *ep;
+    if (arg[0]=='-') die("no options understood");
+
+    errno=0; w= strtoul(arg,&ep,0);
+    if (errno || ep==arg || *ep) die("bad windowid");
+  } else {
+    w= XCreateSimpleWindow(d, DefaultRootWindow(d),
+                          0,0, ui_plan_data.xsz, ui_plan_data.ysz,
+                          0,0, 0);
+    if (w == None) diex("XCreateSimpleWindow", "initial");
+  }
+
+  XCALL( XGetWindowAttributes, 0, (d,w,&wattribs) );
+
+  XPMCALL( XpmCreatePixmapFromData, "background",
+          (d,w, (char**)ui_plan_data.background, &bg_pixmap,0,0) );
+
+  XCALL( XSetWindowBackgroundPixmap, 0, (d,w,bg_pixmap) );
+  XCALL( XFreePixmap, "background", (d,bg_pixmap) );
+
+  XCALL( XAllocNamedColor, "background",
+        (d, wattribs.colormap, ui_plan_colour_off,
+         &background_colour, &background_colour) );
+
+  state= mmalloc(sizeof(*state) * ui_plan_data.n_segments);
+  for (segment_ix= 0, segment_d= ui_plan_data.segments;
+       segment_ix < ui_plan_data.n_segments;
+       segment_ix++, segment_d++) {
+    state[segment_ix]= fs=
+      mmalloc(sizeof(**state) * 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= fs->posn= 0;
+      fs->x= movfeat_d->x;
+      fs->y= movfeat_d->y;
+      fs->redraw_needed= 0;
+      mattribs.valuemask= XpmDepth | XpmColorSymbols;
+      mattribs.depth= 1;
+      mattribs.colorsymbols= coloursymbols;
+      mattribs.numsymbols= sizeof(coloursymbols) / sizeof(*coloursymbols);
+      XPMCALL( XpmCreatePixmapFromData, "mask",
+              (d,w, (char**)movfeat_d->off, &mask,0, &mattribs) );
+      fs->width= mattribs.width;
+      fs->height= mattribs.height;
+
+      gcv.clip_x_origin= fs->x;
+      gcv.clip_y_origin= fs->y;
+      gcv.clip_mask= mask;
+      gcv.foreground= background_colour.pixel;
+      fs->gc= XCreateGC(d,w,
+                       GCClipXOrigin | GCClipYOrigin
+                       | GCClipMask | GCForeground,
+                       &gcv);
+      XCALL( XFreePixmap, "mask", (d,mask) );
+
+      fs->posns= mmalloc(sizeof(*fs->posns)*movfeat_d->n_posns);
+      for (posn= 0; posn < movfeat_d->n_posns; posn++)
+       for (invert=0; invert<2; invert++)
+         for (det=0; det<2; det++) {
+           XPMCALL( XpmCreatePixmapFromData, "main",
+                    (d,w,
+                     (char**)(movfeat_d->posns[posn].a[invert][det]),
+                     &fs->posns[posn][invert][det],
+                     0,0) );
+         }
+    }
+  }
+  
+  sys_events= oop_sys_new();  if (!sys_events) diee("oop_sys_new");
+  events= oop_sys_source(sys_events);  assert(events);
+
+  rd= oop_rd_new_fd(events, 0, 0,0);
+  if (!rd) diee("oop_rd_new_fd");
+  oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
+                  stdin_ifok, 0,
+                  stdin_iferr, 0);
+  if (oor) diee("oop_rd_read");
+
+  events->on_fd(events, 0,                   OOP_EXCEPTION, some_exception, 0);
+  events->on_fd(events, ConnectionNumber(d), OOP_READ,      xlib_readable,  0);
+  events->on_fd(events, ConnectionNumber(d), OOP_EXCEPTION, some_exception, 0);
+
+  XCALL( XSelectInput, 0, (d,w, ExposureMask) );
+
+  if (arg) {
+    XCALL( XClearArea, "initial", (d,w, 0,0,0,0, True) );
+  } else {
+    XCALL( XMapWindow, 0, (d,w) );
+  }
+
+  xlib_process();
+
+  oop_sys_run(sys_events);
+  abort();
+}
diff --git a/hostside/parseutils.c b/hostside/parseutils.c
new file mode 100644 (file)
index 0000000..3c23454
--- /dev/null
@@ -0,0 +1,107 @@
+/**/
+
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hostside.h"
+
+void badcmd(ParseState *ps, const char *fmt, ...) {
+  va_list al;
+  va_start(al,fmt);
+  vbadcmd(ps,fmt,al);
+  va_end(al);
+}
+
+int ps_word(ParseState *ps) {
+  const char *space;
+  if (!ps->remain) return 0;
+  space= strchr(ps->remain, ' ');
+  ps->thisword= ps->remain;
+  if (space) {
+    ps->lthisword= space - ps->thisword;
+    ps->remain= space + 1;
+  } else {
+    ps->lthisword= strlen(ps->remain);
+    ps->remain= 0;
+  }
+  return 1;
+}
+
+int ps_needword(ParseState *ps) {
+  if (!ps_word(ps)) { badcmd(ps,"too few args"); return 0; }
+  return 1;
+}
+
+int ps_neednumber(ParseState *ps, long *r, long mi, long mx, const char *wh) {
+  char *ep;
+  long v;
+  
+  if (!ps_needword(ps)) return 0;
+  errno= 0; v= strtol(ps->thisword,&ep,0);
+  if (errno || ep != ps->thisword + ps->lthisword) {
+    badcmd(ps,"invalid number for %s",wh);
+    return 0;
+  }
+  if (v < mi || v > mx) {
+    badcmd(ps,"%s %ld out of range %ld..%ld",wh,v,mi,mx);
+    return 0;
+  }
+  *r= v;
+  return 1;
+}
+
+int ps_neednoargs(ParseState *ps) {
+  if (ps->remain) {
+    badcmd(ps,"too many arguments");
+    return 0;
+  }
+  return 1;
+}
+int ps_needhextoend(ParseState *ps, Byte *d, int *remain_io) {
+  Byte *d_end;
+  char buf[3], *ep;
+
+  d_end= d + *remain_io;
+  buf[2]= 0;
+  
+  if (!ps->remain) { badcmd(ps,"need hex data block"); return 0; }
+  for (;;) {
+    if (!ps_word(ps)) return 0;
+    while (ps->lthisword > 0) {
+      if (ps->lthisword & 1) {
+       badcmd(ps,"hex data block with odd number of digits in part");
+       return 0;
+      }
+      buf[0]= ps->thisword[0];
+      buf[1]= ps->thisword[1];
+      if (d >= d_end) { badcmd(ps,"hex data block too long"); return 0; }
+      *d++= strtoul(buf,&ep,16);
+      if (*ep) { badcmd(ps,"invalid digit in hex data block"); return 0; }
+      ps->lthisword -= 2;
+      ps->thisword += 2;
+    }
+  }
+
+  *remain_io= d_end - d;
+  return 1;
+}
+
+int lstrstrcmp(const char *a, int la, const char *b) {
+  int lb, minl, r;
+
+  lb= strlen(b);
+  minl= la < lb ? la : lb;
+  r= memcmp(a,b,minl);
+  if (r) return r;
+
+  return (la < lb ? -1 :
+         la > lb ? 1 : 0);
+}
+
+int thiswordstrcmp(ParseState *ps, const char *b) {
+  return lstrstrcmp(ps->thisword, ps->lthisword, b);
+}
+
index 8232ebde401d5f0ac1c3c9a5797f91c5d5724b89..1075de9f9d5fd7e0bd69713c0b2cbb502f271228 100644 (file)
@@ -3,14 +3,9 @@
  */
 
 #include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <assert.h>
-#include <string.h>
 #include <errno.h>
-#include <stdarg.h>
 
-#include <unistd.h>
 #include <fcntl.h>
 
 #include "common.h"
 int serial_fudge_delay= 0;
 int serial_fd= -1;
 
-void vdie(const char *fmt, int ev, va_list al) {
-  vfprintf(stderr,fmt,al);
-  if (ev) fprintf(stderr,": %s",strerror(ev));
-  fputc('\n',stderr);
-  exit(12);
-}
-
-void die(const char *fmt, ...)
-  { va_list al; va_start(al,fmt); vdie(fmt,0,al); }
-void diee(const char *fmt, ...)
-  { va_list al; va_start(al,fmt); vdie(fmt,errno,al); }
-void diem(void)
-  { diee("malloc failed"); }
-
-void *mmalloc(size_t sz) {
-  void *p;
-  if (!sz) return 0;
-  p= malloc(sz);
-  if (!p) diem();
-  return p;
-}
-                 
-char *mstrdupl(const char *s, int l) {
-  char *p;
-  p= mmalloc(l+1);
-  memcpy(p,s,l);
-  p[l]= 0;
-  return p;
-}
-                 
-char *mstrdup(const char *s) { return mstrdupl(s,strlen(s)); }
-
 void serial_open(const char *device) {
   assert(serial_fd==-1);
 
diff --git a/hostside/trackloc.c b/hostside/trackloc.c
new file mode 100644 (file)
index 0000000..4a17714
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ */
+
+#include <assert.h>
+
+#include "safety.h"
+
+const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc) {
+  State *s= &safety_state;
+  SegmentState *seg= &s->segments[tloc->segn];
+  const SegmentInfo *segi= &info_segments[tloc->segn];
+
+  assert(seg->movposcomb < segi->n_poscombs);
+  return &segi->poscombs[seg->movposcomb];
+}
+
+const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc,
+                                           const SegPosCombInfo *pci,
+                                           unsigned far) {
+  return (tloc->backwards ^ far) ? &pci->backwards : &pci->forwards;
+}
+  
+long trackloc_remaininseg(const TrackLocation *tloc) {
+  const SegPosCombInfo *pci;
+  long segment_len;
+
+  pci= trackloc_segposcomb(tloc);
+  segment_len= pci->dist;
+  assert(tloc->into <= segment_len);
+  return segment_len - tloc->into;
+}  
+
+void trackloc_further(TrackLocation *tloc, long *remain_io) {
+  const SegPosCombInfo *pci;
+  const SegmentLinkInfo *lnki_far;
+  long segment_remain;
+
+  segment_remain= trackloc_remaininseg(tloc);
+
+  if (*remain_io <= segment_remain) {
+    tloc->into += *remain_io;
+    *remain_io= 0;
+  } else {
+    pci= trackloc_segposcomb(tloc);
+    lnki_far= trackloc_segmentlink(tloc, pci, 1);
+    *remain_io -= segment_remain;
+    tloc->segn= lnki_far->next;
+    tloc->into= 0;
+    tloc->backwards ^= lnki_far->next_backwards;
+  }
+}
+
+void trackloc_reverse(TrackLocation *tloc) {
+  tloc->into= trackloc_remaininseg(tloc);
+  tloc->backwards ^= 1;
+}
+
index 4a1771448a2e110d3d3ba76251a70ad5db2eb09a..b6c44948f8f7a14fb9b0a4e706f21702c5b2bc9f 100644 (file)
@@ -1,57 +1,41 @@
-/*
- */
+/**/
 
-#include <assert.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
 
-#include "safety.h"
+#include "hostside.h"
 
-const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc) {
-  State *s= &safety_state;
-  SegmentState *seg= &s->segments[tloc->segn];
-  const SegmentInfo *segi= &info_segments[tloc->segn];
-
-  assert(seg->movposcomb < segi->n_poscombs);
-  return &segi->poscombs[seg->movposcomb];
-}
-
-const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc,
-                                           const SegPosCombInfo *pci,
-                                           unsigned far) {
-  return (tloc->backwards ^ far) ? &pci->backwards : &pci->forwards;
+void vdie(const char *fmt, int ev, va_list al) {
+  vfprintf(stderr,fmt,al);
+  if (ev) fprintf(stderr,": %s",strerror(ev));
+  fputc('\n',stderr);
+  exit(12);
 }
-  
-long trackloc_remaininseg(const TrackLocation *tloc) {
-  const SegPosCombInfo *pci;
-  long segment_len;
-
-  pci= trackloc_segposcomb(tloc);
-  segment_len= pci->dist;
-  assert(tloc->into <= segment_len);
-  return segment_len - tloc->into;
-}  
 
-void trackloc_further(TrackLocation *tloc, long *remain_io) {
-  const SegPosCombInfo *pci;
-  const SegmentLinkInfo *lnki_far;
-  long segment_remain;
-
-  segment_remain= trackloc_remaininseg(tloc);
-
-  if (*remain_io <= segment_remain) {
-    tloc->into += *remain_io;
-    *remain_io= 0;
-  } else {
-    pci= trackloc_segposcomb(tloc);
-    lnki_far= trackloc_segmentlink(tloc, pci, 1);
-    *remain_io -= segment_remain;
-    tloc->segn= lnki_far->next;
-    tloc->into= 0;
-    tloc->backwards ^= lnki_far->next_backwards;
-  }
+void die(const char *fmt, ...)
+  { va_list al; va_start(al,fmt); vdie(fmt,0,al); }
+void diee(const char *fmt, ...)
+  { va_list al; va_start(al,fmt); vdie(fmt,errno,al); }
+void diem(void)
+  { diee("malloc failed"); }
+
+void *mmalloc(size_t sz) {
+  void *p;
+  if (!sz) return 0;
+  p= malloc(sz);
+  if (!p) diem();
+  return p;
 }
-
-void trackloc_reverse(TrackLocation *tloc) {
-  tloc->into= trackloc_remaininseg(tloc);
-  tloc->backwards ^= 1;
+                 
+char *mstrdupl(const char *s, int l) {
+  char *p;
+  p= mmalloc(l+1);
+  memcpy(p,s,l);
+  p[l]= 0;
+  return p;
 }
-
+                 
+char *mstrdup(const char *s) { return mstrdupl(s,strlen(s)); }
index 3d64645663ee544db8bc30f7e37b937ee53c2349..fc1c3b4259bfa9dbcbc42a5a3d4608959dbfb35d 100644 (file)
@@ -25,7 +25,8 @@ default:      $(CPROGS) for-test-ui
 all:           default lpages layers extras
 for-test-ui:   ours.graph.c ours.redactgraph ours.raw.neato.ps \
                ours.redacted.neato.ps ours.layout-data.o \
-               ours.dgram-bot.segcmap subseg2display ui-plan-bot.ppm
+               ours.dgram-bot.segcmap subseg2display ui-plan-bot.ppm \
+               ui-plan-bot.o
 
 layers:                $(LAYERS)
 lpages:                $(LPAGES)
index c5f9081a20eac244dd73c13582da877473643a36..e9ce03a797f5f81d2bcac9199076d8453b35cf63 100644 (file)
@@ -10,21 +10,27 @@ typedef struct {
 } PlanPixmapOnData;
 
 typedef struct {
-  unsigned long code;
+  const char *movfeatname;
+  int x, y;
   PlanPixmapDataRef off;
   int n_posns;
   const PlanPixmapOnData *posns;
 } PlanSegmovfeatData;
 
 typedef struct {
+  const char *segname;
   int n_movfeats;
   const PlanSegmovfeatData *movfeats;
 } PlanSegmentData;
 
 typedef struct {
+  int xsz, ysz;
   PlanPixmapDataRef background;
   int n_segments;
   const PlanSegmentData *segments;
 } PlanData;
 
+extern const PlanData ui_plan_data;
+extern const char ui_plan_colour_off[];
+
 #endif /*PLAN_DATA_FORMAT_H*/
index 391334f933d59636a59c714df5d6d79064bcdf43..9deb5d04fce309de9a343ed725cd8f65eb49c3ca 100755 (executable)
@@ -219,6 +219,7 @@ sub in_pixel () {
        }
        die "$pp $t{Movfeatpos}"
            unless defined $found;
+       $xpmname= $segname.'_'.$found;
        for ($bitno=0; $bitno < $movfeat_configbits{$xpmname}; $bitno++) {
            xpmdata_pixel("on","_${xpmname}_${bitno}",
                          ((1<<$bitno) & $t{Movfeatpos}) ? $angstr : '-');
@@ -242,6 +243,7 @@ our (%cmap,%stylecmaps);
 # $cmap{$cmapname}{$pixchars}= $xpm_data_string_rhs
 # $cmap{$cmapname}{''}= [ string names for including in xpm ]
 #                          (after cmapdata_output_all)
+$cmap{''}= {}; # fixed colours
 
 sub xpm_cmap ($$) {
     my ($style,$cmapname) = @_;
@@ -252,6 +254,7 @@ sub xpm_cmap ($$) {
 
 sub xpm_cmap_entry ($$$) {
     my ($cmapname,$pixchars,$rhs) = @_;
+    die unless exists $cmap{$cmapname};
     die if exists $cmap{$cmapname}{$pixchars};
     $cmap{$cmapname}{$pixchars}= $rhs;
 }
@@ -317,19 +320,22 @@ sub xpm_cmap_angular($$$@) {
 
 sub cmaps_define () {
     my ($inv,$ondet);
-    
+
     xpm_cmap("background","background");
+    xpm_cmap_rgbpermil('',qw(off 0 0 0));
     xpm_cmap_rgbpermil("background",qw(- 100 100 100
-                                      + 999 0 999
+                                      + 999 0 990
                                       : 75 75 75
-                                      ! 999 0 999));
+                                      ! 999 0 980));
     xpm_cmap("off","off");
     xpm_cmap_fixedbitmap("off",'*');
 
     foreach $inv (('','i')) {
        foreach $ondet (qw(on det)) {
            xpm_cmap("on","${inv}${ondet}");
-           xpm_cmap_rgbpermil("${inv}${ondet}",qw(- 300 300 300));
+           xpm_cmap_rgbpermil("${inv}${ondet}",
+                              ' ', qw(999 0 970),
+                              qw(- 50 50 50));
        }
        xpm_cmap_angular("${inv}on", !!$inv, 600, qw(0 0 0));
        xpm_cmap_angular("${inv}det",!!$inv, 330, qw(1000 1000 1000));
@@ -342,7 +348,9 @@ cmaps_define();
 
 sub cmapdata_output_all () {
     my ($cmapname, $stuff, $cmap, $sname, $pixchars);
+
     foreach $cmapname (sort keys %cmap) {
+       next unless length $cmapname;
        $stuff= [ ];
        $cmap= $cmap{$cmapname};
        foreach $pixchars (sort keys %$cmap) {
@@ -354,6 +362,16 @@ sub cmapdata_output_all () {
        }
        $cmap->{''}= $stuff;
     }
+
+    my ($colour, $rhs);
+    $cmap= $cmap{''};
+    foreach $colour (sort keys %$cmap) {
+       $rhs= $cmap->{$colour};
+       $rhs =~ s/^c // or die "$colour $rhs ?";
+       printf("const char ui_plan_colour_%s[]= \"%s\";\n",
+              $colour, $rhs)
+           or die $!;
+    }
 }
 
 sub xpmdata_output_all () {
@@ -409,6 +427,7 @@ die "$pp ?" if $xp->{X}{Max} >= 642;
 sub plandata_output_all () {
     my ($i, @segnames, $segname);
     my (@movfeats, $movfeat, $dname, $xpmname, $n_posns, $code, $posn, $mfd);
+    my ($n_movfeats, $xpmd);
     for ($i=1; $i<@segnum_name; $i++) {
        next unless defined $segnum_name[$i];
        push @segnames, $segnum_name[$i];
@@ -425,11 +444,11 @@ sub plandata_output_all () {
            if (!length $movfeat) {
                $xpmname= $segname;
                $n_posns= 1;
-               $code= 0;
+               $code= '0';
            } else {
                $xpmname= "${segname}_${movfeat}";
                $n_posns= $movfeat_configbits{$xpmname};
-               $code= $movfeat_prefix{$xpmname};
+               $code= "\"$movfeat\"";
            }
            printf("static const PlanPixmapOnData pon_%s[]= {\n",
                   $xpmname)
@@ -446,8 +465,11 @@ sub plandata_output_all () {
            }
            printf("};\n")
                or die $!;
-           $mfd .= sprintf("  { 0x%x, p_off_%s, %d, pon_%s },\n",
-                           $code, $xpmname, $n_posns, $xpmname);
+           $xpmd= $xpmdata{'off'}{"_$xpmname"};
+           $mfd .= sprintf("  { %s, %d,%d, p_off_%s, %d, pon_%s },\n",
+                           $code,
+                           $xpmd->{X}{Min}, $xpmd->{Y}{Min},
+                           $xpmname, $n_posns, $xpmname);
        }
        printf("static const PlanSegmovfeatData mf_%s[]= {\n".
               "%s".
@@ -459,19 +481,20 @@ sub plandata_output_all () {
        or die $!;
     for $segname (@segnames) {
        if (exists $movfeats{$segname}) {
-           printf("  { %d, mf_%s },\n",
-                  scalar(@{ $movfeats{$segname} })+1,
-                  $segname)
-               or die $!;
+           $n_movfeats= scalar(@{ $movfeats{$segname} })+1;
        } else {
-           printf("  { 1, mf_%s },\n",
-                  $segname)
-               or die $!;
+           $n_movfeats= 1;
        }
+       printf("  { \"%s\", %d, mf_%s },\n",
+              $segname,
+              $n_movfeats,
+              $segname)
+           or die $!;
     }
     printf("};\n")
        or die $!;
     printf("const PlanData ui_plan_data= {\n".
+          "  $sz{X}, $sz{Y},\n".
           "  p_background,\n".
           "  %d, segments\n".
           "};\n",