summaryrefslogtreecommitdiff
path: root/target/alphix.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/alphix.c')
-rw-r--r--target/alphix.c468
1 files changed, 468 insertions, 0 deletions
diff --git a/target/alphix.c b/target/alphix.c
new file mode 100644
index 0000000..68dfd48
--- /dev/null
+++ b/target/alphix.c
@@ -0,0 +1,468 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Alphabetic index class.
+ *
+ * Author: Graeme W. Gill
+ * Date: 22/8/2005
+ *
+ * Copyright 2005, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* TTBD:
+ It would be nice if it was possible to add a delimeter between
+ the X and Y identifiers so that number + number or alpha + alpha
+ identification was possible.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "numsup.h"
+#include "alphix.h"
+
+/* Return the alpha index for the given raw index number */
+/* Return NULL on error */
+static char *torawix(alphix *p, int ix) {
+ int i, j, n;
+ int z = 0;
+ char *rv, *v;
+
+ if (ix < 0 || ix >= p->rmct)
+ return NULL; /* Index range error */
+
+ if ((rv = malloc((p->nd+1) * sizeof(char))) == NULL)
+ return NULL;
+
+ for (v = rv, j = 0, i = p->nd-1; i >= 0; j++, i--) {
+ char c;
+ n = ix / p->ds[i].b;
+ ix -= n * p->ds[i].b;
+ c = p->ds[i].seq[n];
+ if (p->ds[i].z && z == 0 && c == '0')
+ c = ' ';
+ if (z != 0 || c != ' ') {
+ *v++ = p->ds[i].seq[n];
+ z = 1;
+ }
+ }
+ *v = '\000';
+
+ return rv;
+}
+
+/* Return the the raw index number given the alpha index */
+/* return -1 on error */
+static int fromanat(alphix *p, char *ax) {
+ char *v, *tb, _tb[11];
+ int cl;
+ int i, k, rv = 0;
+
+ if (p->nd > 10) {
+ if ((tb = malloc((p->nd+1) * sizeof(char))) == NULL)
+ return -1; /* Malloc error */
+ } else
+ tb = _tb;
+
+ /* Pack the string out to the right number of digits with spaces. */
+ cl = strlen(ax);
+ for (v = tb; cl < p->nd; v++, cl++)
+ *v = ' ';
+ strcpy(v, ax);
+
+ /* For each digit, convert to numerical and accumulate */
+ for (v = tb, i = p->nd-1; i >= 0; v++, i--) {
+ for (k = 0; k < p->ds[i].n; k++) {
+ if (*v == p->ds[i].seq[k]
+ || (p->ds[i].z && *v == ' ' && p->ds[i].seq[k] == '0')) {
+ rv += k * p->ds[i].b;
+ break;
+ }
+ }
+ if (k >= p->ds[i].n) {
+ if (tb != _tb)
+ free(tb);
+ return -1; /* Unknown digit */
+ }
+ }
+
+ if (tb != _tb)
+ free(tb);
+
+ return rv;
+}
+
+/* Working from the end of the string, */
+/* return a pointer to the maximum number of characters */
+/* that are legaly part of this alpha index. */
+static char *find_start(alphix *p, char *ax) {
+ int i, k;
+ char *v;
+
+ v = ax + strlen(ax) - 1; /* start at last character */
+ for (i = 0; v >= ax && i < p->nd; v--, i++) { /* working backwards */
+ for (k = 0; k < p->ds[i].n; k++) { /* Locate */
+ if (*v == p->ds[i].seq[k])
+ break; /* Found */
+ }
+ if (k >= p->ds[i].n) /* Not found */
+ break;
+ }
+ return v+1;
+}
+
+/* Convert from cooked index to raw index. */
+/* Return -1 if out of range */
+static int cookedtoraw(alphix *p, int ix) {
+ int i;
+
+ if (p->nr == 0)
+ return ix;
+
+ for (i = 0; i < p->nr; i++) {
+ if (ix >= p->rs[i].c0 && ix <= p->rs[i].c1) {
+ ix = ix - p->rs[i].c0 + p->rs[i].r0;
+ return ix;
+ }
+ }
+ return -1;
+}
+
+/* Convert from raw index to cooked index. */
+/* Return -1 if out of range */
+static int rawtocooked(alphix *p, int ix) {
+ int i;
+
+ if (p->nr == 0)
+ return ix;
+
+ for (i = 0; i < p->nr; i++) {
+ if (ix >= p->rs[i].r0 && ix <= p->rs[i].r1) {
+ ix = ix - p->rs[i].r0 + p->rs[i].c0;
+ return ix;
+ }
+ }
+ return -1;
+}
+
+/* Return the maximum possible length of count */
+static int alphix_maxlen(alphix *p) {
+ return p->cmct;
+}
+
+/* Return the alpha index for the given index number (0 based) */
+/* Return NULL on error */
+/* (Free after use) */
+static char *alphix_aix(alphix *p, int ix) {
+ if ((ix = cookedtoraw(p, ix)) < 0)
+ return NULL;
+ return torawix(p, ix);
+}
+
+/* Return the index number for the given alpha index */
+int alphix_nix(alphix *p, char *ax) {
+ int rv;
+ if ((rv = fromanat(p, ax)) < 0)
+ return -1;
+ return rawtocooked(p, rv);
+}
+
+/* Destroy ourselves */
+static void
+alphix_del(alphix *p) {
+ int i;
+ for (i = 0; i < p->nd; i++)
+ free(p->ds[i].seq);
+ free (p->ds);
+ free (p->rs);
+ free (p);
+}
+
+/* Constructor: */
+alphix *new_alphix(char *pattern) {
+ alphix *p;
+ char *pp = pattern;
+ int i;
+
+ if ((p = (alphix *)calloc(1,sizeof(alphix))) == NULL)
+ error("alphix: malloc failed");
+
+ p->maxlen = alphix_maxlen;
+ p->aix = alphix_aix;
+ p->nix = alphix_nix;
+ p->del = alphix_del;
+
+ /* We now need to parse the pattern to setup our index sequence: */
+ /* For all digits */
+ for (p->nd = 0; ; p->nd++) {
+
+ if (*pp == '\000' || *pp == ';') {
+ break;
+ }
+
+ /* We are starting a new digit sequence */
+ if (p->nd >= p->_nd) { /* Allocate space for current digit */
+ p->_nd = 2 + p->_nd;
+ if ((p->ds = (dig *)realloc(p->ds, p->_nd * sizeof(dig))) == NULL)
+ error ("alphix: realloc failed");
+ }
+
+ p->ds[p->nd].n = 0;
+ p->ds[p->nd].seq = NULL;
+ p->ds[p->nd]._n = 0;
+ p->ds[p->nd].z = 0;
+
+ /* For all symbols in this digit */
+ for (p->ds[p->nd].n = 0; ;) {
+ char c, c1, c2;
+
+ /* We are adding another character to the sequence */
+ if (*pp == '\000' || *pp == ';' || *pp == ',')
+ break; /* Done this digit */
+ if (pp[1] == '-' && pp[2] != '\000' && pp[2] != ';' && pp[2] != ',') {
+ c1 = pp[0];
+ c2 = pp[2];
+ pp += 3;
+ } else {
+ c1 = c2 = *pp;
+ pp++;
+ }
+ if (c1 == '@') {
+ c1 = '0';
+ p->ds[p->nd].z = 1;
+ }
+ if (c2 == '@') {
+ c2 = '0';
+ p->ds[p->nd].z = 1;
+ }
+
+ /* Expand digit sequence */
+ for (c = c1; c <= c2; c++) {
+
+ if (p->ds[p->nd].n >= p->ds[p->nd]._n) { /* Allocate space for next character */
+ p->ds[p->nd]._n = 20 + p->ds[p->nd]._n;
+ if ((p->ds[p->nd].seq = (char *)realloc(p->ds[p->nd].seq, p->ds[p->nd]._n * sizeof(char))) == NULL)
+ error ("alphix: realloc failed");
+ }
+ p->ds[p->nd].seq[p->ds[p->nd].n++] = c;
+ }
+ }
+ if (*pp == '\000' || *pp == ';')
+ continue;
+ pp++;
+
+ }
+
+ /* Compute the native maximum index count */
+ for (p->rmct = 1, i = 0; i < p->nd; i++) {
+ p->ds[i].b = p->rmct;
+ p->rmct *= p->ds[i].n;
+ }
+
+ /* Search for valid ranges */
+ if (*pp == ';') {
+ char *v, *tb, _tb[11];
+
+ pp++;
+ if (p->nd > 10) {
+ if ((tb = malloc((p->nd+1) * sizeof(char))) == NULL)
+ error ("alphix: malloc failed");
+ } else
+ tb = _tb;
+
+ /* For each range */
+ for (p->nr = 0; ; p->nr++) {
+
+ if (*pp == '\000' || *pp == ';')
+ break;
+
+ /* We are adding a new range */
+ if (p->nr >= p->_nr) { /* Allocate space for current range */
+ p->_nr = 2 + p->_nr;
+ if ((p->rs = (rngsq *)realloc(p->rs, p->_nr * sizeof(rngsq))) == NULL)
+ error ("alphix: realloc failed");
+ }
+
+ /* Locate the end of the range start */
+ for(v = tb; *pp != '\000' && *pp != '-' && *pp != ','; v++, pp++)
+ *v = *pp;
+ *v = '\000';
+ p->rs[p->nr].r0 = p->rs[p->nr].r1 = fromanat(p, tb);
+ if (p->rs[p->nr].r0 < 0)
+ error("alphix: range start definition error on '%s'",tb);
+
+
+ if (*pp != '-') { /* oops - bad definition */
+ error("alphix: range definition error - missing '-'");
+ }
+
+ /* Locate the end of the range end */
+ for(v = tb, pp++; *pp != '\000' && *pp != ','; v++, pp++)
+ *v = *pp;
+ *v = '\000';
+ p->rs[p->nr].r1 = fromanat(p, tb);
+ if (p->rs[p->nr].r1 < 0)
+ error("alphix: range end definition error on '%s'",tb);
+
+ if (p->rs[p->nr].r1 < p->rs[p->nr].r0) /* Hmm */
+ error("alphix: range definition error, end < start ");
+
+ /* Compute cooked index range */
+ p->rs[p->nr].c0 = 0;
+ p->rs[p->nr].c1 = p->rs[p->nr].r1 - p->rs[p->nr].r0;
+ if (p->nr > 0) {
+ int ofs = p->rs[p->nr-1].c1+1;
+ p->rs[p->nr].c0 += ofs;
+ p->rs[p->nr].c1 += ofs;
+ }
+
+ if (*pp == '\000' || *pp == ';')
+ continue;
+ pp++;
+ }
+
+ if (tb != _tb)
+ free(tb);
+ }
+
+ /* Compute cooked actual range */
+ p->cmct = p->rmct;
+ if (p->nr > 0) {
+ p->cmct = p->rs[p->nr-1].c1+1;
+ }
+
+#ifdef NEVER
+ // ###########################################################
+ /* Debug stuff */
+ printf("~1 There are %d digits, %d ranges, raw max = %d, cooked max = %d\n",
+ p->nd,p->nr,p->rmct, p->maxlen(p));
+
+ /* Digit sequences */
+ for (i = 0; i < p->nd; i++) {
+ printf(" ~1 Digit %d has %d symbols\n",i,p->ds[i].n);
+ for (j = 0; j < p->ds[i].n; j++)
+ printf(" ~1 symbol %d = '%c'\n",j,p->ds[i].seq[j]);
+ }
+
+ /* Ranges */
+ for (i = 0; i < p->nr; i++) {
+ printf(" ~1 Range %d is raw %d - %d, cooked %d - %d\n",
+ i,p->rs[i].r0, p->rs[i].r1, p->rs[i].c0, p->rs[i].c1);
+ }
+
+ /* Itterate the sequence */
+ for (i = 0; i < p->cmct; i++) {
+ char *v;
+ v = p->aix(p, i);
+ printf("ix %d -> '%s'\n",i,v);
+ free(v);
+ }
+ // ###########################################################
+#endif /* NEVER */
+
+ return p;
+}
+
+
+/* ==================================================================== */
+/* Utility function: */
+/* Given the strip and patch alphix objects, and order flag, */
+/* Return a patch location. Free the returned string after use. */
+/* Return NULL on error */
+char *patch_location(
+ alphix *saix, /* Strip alpha index object */
+ alphix *paix, /* Patch alpha index object */
+ int ixord, /* Index order, 0 = strip then patch */
+ int six, /* Strip index */
+ int pix /* Patch index */
+) {
+ char *sl, *pl, *rv;
+ int ll;
+
+ if ((sl = saix->aix(saix, six)) == NULL)
+ return NULL;
+
+ if ((pl = paix->aix(paix, pix)) == NULL) {
+ free (sl);
+ return NULL;
+ }
+ ll = strlen(sl) + strlen(pl) + 1;
+ if ((rv = malloc(ll * sizeof(char))) == NULL) {
+ free (pl);
+ free (sl);
+ return NULL;
+ }
+
+ if (ixord == 0) {
+ strcpy (rv, sl);
+ strcat (rv, pl);
+ } else {
+ strcpy (rv, pl);
+ strcat (rv, sl);
+ }
+ return rv;
+}
+
+/* ==================================================================== */
+/* Utility function: */
+/* Given the strip and patch alphix objects, and order flag, */
+/* and a corresonding patch location string, return an index */
+/* number suitable for sorting location strings. */
+/* The sort order is in order of strips, then patches within each strip */
+/* Return -1 on error */
+int patch_location_order(
+ alphix *saix, /* Strip alpha index object */
+ alphix *paix, /* Patch alpha index object */
+ int ixord, /* Index order, 0 = strip then patch */
+ char *_ax /* Patch location string */
+) {
+ char *ax; /* Copy of input string */
+ char *v;
+ alphix *rh; /* Least significant, right hand alphix */
+ alphix *lh; /* Most significant, left hand alphix */
+ int ri, li; /* Right hand and left hand index numbers */
+
+ if ((ax = malloc(strlen(_ax)+1)) == NULL)
+ return -1;
+ strcpy(ax,_ax);
+
+ if (ixord == 0) {
+ lh = saix; /* Strip is left hand */
+ rh = paix; /* Patch is right hand */
+ } else {
+ rh = saix; /* Strip is right hand */
+ lh = paix; /* Patch is left hand */
+ }
+
+ /* We need to identify the boundary between */
+ /* the right hand and left hand indexes. */
+ /* We assume that the sequences are distinguishable ... */
+ v = find_start(rh, ax);
+
+ ri = rh->nix(rh, v);
+ *v = '\000';
+ li = lh->nix(lh, ax);
+ free(ax);
+ if (ri < 0 || li < 0)
+ return -1;
+
+ if (ixord == 0) /* Strip is left hand */
+ return li * rh->cmct + ri;
+ else
+ return ri * lh->cmct + li;
+}
+
+
+
+
+
+
+
+
+
+