* subseg2display encoding.ppm [status-info ...]
*
* status-info args are:
- * <subseg> <alpha> <red> <green> <blue>
+ * <idchar> <alpha> <red> <green> <blue>
+ * .. <alpha> <red> <green> <blue>
+ * <idchar><subseg>
+ *
+ * `..' group is for unspecified segments.
*
* <subseg> is
* <segnum> for fixed track
* <segnum>.<movfeatpos> for part of a moveable feature
- * where numbers are in strtoul format, movfeatpos is the
+ * where numbers are in strtoul base=0 format, movfeatpos is the
* moveable feature and position as in segcmapassign and
- * if <subseg> is `.', spec is for unspecified segments.
*
* Resulting pixel is
* [ red ]
* (alpha * DIRECTION_COLOUR) + ((1-alpha) * [ green ] )
* [ blue ]
- *
- * status.bin has the following format:
- * 16 bits number of segments
- * 2
*/
-int main(int argc, const char *const *argv) {
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <math.h>
+
+#include <publib.h>
+#include <ppm.h>
+
+/*---------- lookup data structure ----------*/
+
+struct idinfo {
+ double alpha, red, green, blue;
+};
+
+typedef unsigned char id;
+
+struct movperseg {
+ id *lookup;
+ int lookup_a;
+};
+
+#define NCHARS 256
+#define MAXSEGNUM ((1<<10)-1)
+#define MAXMOVFEATPOS ((1<<6)-1)
+
+static struct idinfo idinfo[NCHARS];
+
+static id *fixed;
+static int fixed_a;
+
+static struct movperseg *moveable;
+static int moveable_a;
+
+/*---------- arg parsing helper routines ----------*/
+
+static char **argv;
+
+static void badusage(void) {
+ fprintf(stderr,"bad usage\n");
+ exit(12);
+}
+
+static const char *nextarg(void) {
+ if (!*argv) badusage();
+ return *argv++;
+}
+
+static double doublearg(void) {
+ const char *arg= nextarg();
+ char *ep;
+ double v;
+
+ errno= 0;
+ v= strtod(arg,&ep);
+ if (*ep) badusage();
+ if (errno) badusage();
+ if (!finite(v)) badusage();
+
+ return v;
+}
+
+/*---------- specification args ----------*/
+
+static void idgroupargs(id ix) {
+ struct idinfo *r;
+
+ r= &idinfo[ix];
+
+ r->alpha = doublearg();
+ r->red = doublearg();
+ r->green = doublearg();
+ r->blue = doublearg();
+}
+
+static void ensure_somethings(void **ary, int *allocd, int want, size_t item,
+ void zero(void *data, int count)) {
+ int new_allocd;
+
+ if (*allocd > want) return;
+ new_allocd= (*allocd+1)*2;
+ *ary= xrealloc(*ary, new_allocd * item);
+ zero((char*)*ary + item * *allocd, new_allocd - *allocd);
+ *allocd= new_allocd;
+}
+
+static void zero_ids(void *data, int count) {
+ memset(data,0, count*sizeof(id));
+}
+
+static void zero_mps(void *data_v, int count) {
+ struct movperseg *data= data_v;
+ for (count /= sizeof(*data);
+ count > 0;
+ count--, data++) {
+ data->lookup= 0;
+ data->lookup_a= 0;
+ }
+}
+
+#define ENSURE_THINGS(sfx,type) \
+ static void ensure_##sfx(type **ary_io, int *allocd, int want) { \
+ void *ary= *ary_io; \
+ ensure_somethings(ary,allocd,want,sizeof(**ary_io),zero_##sfx); \
+ *ary_io= ary; \
+ } \
+ struct eat_semicolon
+
+ENSURE_THINGS(ids,id);
+ENSURE_THINGS(mps,struct movperseg);
+
+static void subsegarg(id ix, const char *arg) {
+ struct idinfo *r;
+ struct movperseg *mps;
+ unsigned long segnum, movfeatpos;
+ char *ep;
+
+ r= &idinfo[ix];
+
+ errno= 0;
+ segnum= strtoul(arg,&ep,0);
+ if (errno) badusage();
+ if (segnum > MAXSEGNUM) badusage();
+
+ if (!*ep) {
+ ensure_ids(&fixed,&fixed_a,segnum);
+ fixed[segnum]= ix;
+ return;
+ }
+
+ if (*ep != '.') badusage();
+
+ errno= 0;
+ movfeatpos= strtoul(ep+1,&ep,0);
+ if (*ep || errno) badusage();
+ if (movfeatpos > MAXMOVFEATPOS) badusage();
+
+ ensure_mps(&moveable,&moveable_a,segnum);
+ mps= &moveable[ix];
+ ensure_ids(&mps->lookup,&mps->lookup_a, movfeatpos ^ MAXMOVFEATPOS);
+ mps->lookup[movfeatpos ^ MAXMOVFEATPOS]= ix;
+}
+
+/*---------- actual image processing ----------*/
+
+static int cols, rows, informat;
+static pixval maxval;
+static FILE *encodingfile;
+
+static void badformat(const char *m) {
+ fprintf(stderr,"bad format: %s\n", m);
+ exit(12);
+}
+
+static void process(void) {
+ ppm_readppminit(encodingfile, &cols, &rows, &maxval, &informat);
+ if (maxval != 255) badformat("bad maxval");
+ if (informat != RPPM_FORMAT) badformat("bad format");
+ ppm_writeppminit(stdout, cols, rows, 255, 0);
+}
+
+int main(int argc_spec, char **argv_spec) {
+ const char *arg, *encodingfilename;
+
+ ppm_init(&argc_spec,argv_spec);
+
+ argv= argv_spec;
+ nextarg();
+ encodingfilename= nextarg();
+ while (*argv) {
+ arg= nextarg();
+ if (!*arg) badusage();
+ if (!arg[1]) idgroupargs(arg[0]);
+ else if (!strcmp(arg,"..")) idgroupargs(0);
+ else subsegarg(arg[0],arg+1);
+ }
+
+ encodingfile= fopen(encodingfilename, "rb");
+ if (!encodingfile) { perror(encodingfilename); exit(8); }
+ process();
+ return 0;
}