int main ( int argc , const char* argv[] ) { int a = 0 ; mcxTing* argtxt = mcxTingEmpty(NULL, 10) ; if (0) mclxIOsetQMode("MCLXIOVERBOSITY", MCL_APP_VB_NO) ; opInitialize() /* symtable etc */ ; globInitialize() /* hdltable etc */ ; if (argc == 1) { mcxTing* ops = mcxTingEmpty(NULL, 20) ; mcxIO *xfin = mcxIOnew("-", "r") ; mcxIOopen(xfin, EXIT_ON_FAIL) ; fprintf ( stdout , "At your service: " "'[/<op>] help', '[/<str>] grep', 'ops', 'info', and 'quit'.\n" ) ; while (1) { int ok ; mcxTing* line = mcxTingEmpty(NULL, 30) ; fprintf(stdout, "> ") ; fflush(stdout) ; if (STATUS_OK != mcxIOreadLine(xfin, line, MCX_READLINE_BSC)) { fprintf(stdout, "curtains!\n") ; mcxTingFree(&line) ; break ; } mcxTingAppend(ops, line->str) ; mcxTingFree(&line) ; ok = zsDoSequence(ops->str) ; if (ok && (v_g & V_STACK)) zsList(0) ; mcxTingEmpty(ops, 20) ; } } else { for (a=1;a<argc;a++) { mcxTingWrite(argtxt, argv[a]) ; if (!zgUser(argtxt->str)) mcxExit(1) ; } } mcxTingFree(&argtxt) ; return 0 ; }
static mclx* process_queries ( mcxIO* xq , mclx* mx , mclx* mxtp , mcxIO* xfmx , mclTab* tab , mcxIO* xfout , mcxIO* xfpath , mcxIO* xfstep ) { mcxTing* line = mcxTingEmpty(NULL, 100) ; mcxTing* sa = mcxTingEmpty(NULL, 100) ; mcxTing* sb = mcxTingEmpty(NULL, 100) ; SSPxy* sspo = mclgSSPxyNew(mx, mxtp) ; mcxIOopen(xq, EXIT_ON_FAIL) ; while (1) { long a = -1, b = -2, ns = 0 ; mcxbool query = FALSE ; if (isatty(fileno(xq->fp))) fprintf ( stdout , "\n(ready (expect two %s or : directive))\n" , tab ? "labels" : "graph indices" ) ; if ( STATUS_OK != mcxIOreadLine(xq, line, MCX_READLINE_CHOMP) || !strcmp(line->str, ".") ) break ; query = (u8) line->str[0] == ':' ; if (query && (line->len == 1 || isspace((unsigned char) line->str[1]))) { fprintf(xfout->fp, "-->\n") ; fprintf(xfout->fp, ":tf <tf-spec>\n") ; fprintf(xfout->fp, ":top <num>\n") ; fprintf(xfout->fp, ":list <node>\n") ; fprintf(xfout->fp, ":clcf <node>\n") ; fprintf(xfout->fp, ":reread>\n") ; fprintf(xfout->fp, "<--\n") ; continue ; } mcxTingEnsure(sa, line->len) ; mcxTingEnsure(sb, line->len) ; ns = sscanf(line->str, "%s %s", sa->str, sb->str) ; if (ns == 2) sa->len = strlen(sa->str) , sb->len = strlen(sb->str) ; else sa->len = strlen(sa->str) , sb->len = 0 , sb->str[0] = '\0' ; if (!query && ns != 2) { if (line->len) fprintf(stderr, "(error expect two nodes or : directive)\n") ; continue ; } if (query) { mx = handle_query(mx, xfmx, sa, sb) ; sspo->mx = mx /* fixme improve ownership handling */ ; sspo->mxtp = mx ; fprintf(xfout->fp, "%s\n\n", line->str) ; continue /* fixme improve flow */ ; } else if (tab) { mcxKV* kv ; if ((kv = mcxHashSearch(sa, hsh_g, MCX_DATUM_FIND))) a = VOID_TO_ULONG kv->val /* fixme (> 2G labels) */ ; else { label_not_found(sa) ; continue ; } if ((kv = mcxHashSearch(sb, hsh_g, MCX_DATUM_FIND))) b = VOID_TO_ULONG kv->val /* fixme (> 2G labels) */ ; else { label_not_found(sb) ; continue ; } } else if (mcxStrTol(sa->str, &a, NULL) || mcxStrTol(sb->str, &b, NULL)) { fprintf(stderr, "(error failed-reading-number)\n") ; continue ; } if (check_bounds(mx, a)) continue ; if (check_bounds(mx, b)) continue ; fprintf ( xfout->fp , "\n(lattice\n" " (anchors %s %s)\n" , sa->str , sb->str ) ; if (0 && a == b) { fprintf ( xfout->fp , " (path-length 0)\n" "(data\n" ) ; } else { mcxstatus thestat = mclgSSPxyQuery(sspo, a, b) ; dim t ; if (thestat) fprintf(xfout->fp, " (path-length -2)\n(data\n") ; else if (sspo->length < 0) /* not in same component */ fprintf(xfout->fp, " (path-length -1)\n(data\n") ; else { fprintf ( xfout->fp , " (path-length %d)\n" "(data\n" , (int) sspo->length ) ; if (sspo->length == 1) { if (tab) fprintf(xfout->fp, "((%s %s))\n", sa->str, sb->str) ; else fprintf(xfout->fp, "((%ld %ld))\n", (long) a, (long) b) ; } else for (t=0; t< N_COLS(sspo->pathmx)-1; t++) erdos_link_together(xfout, mx, sspo->pathmx->cols+t, sspo->pathmx->cols+t+1) ; fputs(")\n", xfout->fp) ; fprintf(xfout->fp, " (anchors %s %s)\n", sa->str, sb->str) ; fprintf(xfout->fp, " (considered %d)\n", (int) sspo->n_considered) ; fprintf(xfout->fp, " (participants %d)\n", (int) sspo->n_involved) ; fprintf(xfout->fp, " (path-length %d)\n", (int) sspo->length) ; } } fprintf(xfout->fp, ")\n\n") ; if (xfpath) mclxWrite(sspo->pathmx, xfpath, MCLXIO_VALUE_NONE, RETURN_ON_FAIL) ; if (xfstep) mclxWrite(sspo->stepmx, xfstep, MCLXIO_VALUE_GETENV, RETURN_ON_FAIL) ; mclgSSPxyReset(sspo) ; } mcxTingFree(&sa) ; mcxTingFree(&sb) ; mcxTingFree(&line) ; mclgSSPxyFree(&sspo) ; return mx ; }
static mcxstatus read_123 ( mcxIO* xf , mcxTing* buf , stream_state* iface , mclxIOstreamer* streamer , double* value , mcxbits bits ) { mcxstatus status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP) ; int cv = 0 ; const char* printable ; const char* me = module ; mcxbool strict = bits & MCLXIO_STREAM_STRICT ; mcxbool warn = bits & MCLXIO_STREAM_WARN ; unsigned long x = 0, y = 0 ; while (1) { if (status) break ; status = STATUS_FAIL ; printable = mcxStrChrAint(buf->str, isspace, buf->len) ; if (printable && (unsigned char) printable[0] == '#') { status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP) ; continue ; } cv = sscanf(buf->str, "%lu%lu%lf", &x, &y, value) ; if (x > LONG_MAX || y > LONG_MAX) { mcxErr (me, "negative values in input stream? unsigned %lu %lu", x, y) ; break ; } if (cv == 2) *value = 1.0 ; else if (cv != 3) { if (strict || warn) mcxErr ( module , "123-parser chokes at line %ld [%s]" , (long) xf->lc , buf->str ) ; if (strict) break ; status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP) ; continue ; } else if (!(*value < FLT_MAX)) *value = 1.0 ; if ( (streamer->cmax_123 && x >= streamer->cmax_123) || (streamer->rmax_123 && y >= streamer->rmax_123) ) { status = STATUS_IGNORE ; break ; } status = STATUS_OK ; break ; } if (!status) { iface->x = x ; iface->y = y ; if (iface->map_c->max_seen+1 < x+1) /* note mixed-sign comparison */ iface->map_c->max_seen = x ; if (iface->map_r->max_seen+1 < y+1) /* note mixed-sign comparison */ iface->map_r->max_seen = y ; } return status ; }
static mcxstatus read_abc ( mcxIO* xf , mcxTing* buf , stream_state *iface , double* value ) { mcxstatus status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP) ; mcxTing* xkey = mcxTingEmpty(NULL, buf->len) ; mcxTing* ykey = mcxTingEmpty(NULL, buf->len) ; mcxbits bits = iface->bits ; mcxbool strict = bits & MCLXIO_STREAM_STRICT ; mcxbool warn = bits & MCLXIO_STREAM_WARN ; mcxbool label_cbits = bits & (MCLXIO_STREAM_CTAB_STRICT | MCLXIO_STREAM_CTAB_RESTRICT) ; mcxbool label_rbits = bits & (MCLXIO_STREAM_RTAB_STRICT | MCLXIO_STREAM_RTAB_RESTRICT) ; mcxbool label_dbits = bits & (MCLXIO_STREAM_WARN | MCLXIO_STREAM_DEBUG) ; const char* printable ; int cv = 0 ; iface->statusx = STATUS_OK ; iface->statusy = STATUS_OK ; do { int xlen = 0 ; int ylen = 0 ; if (status) break ; printable = mcxStrChrAint(buf->str, isspace, buf->len) ; if (printable && (uchar) printable[0] == '#') { status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP) ; continue ; } mcxTingEnsure(xkey, buf->len) /* fixme, bit wasteful */ ; mcxTingEnsure(ykey, buf->len) /* fixme, bit wasteful */ ; cv = strchr(buf->str, '\t') ? sscanf(buf->str, "%[^\t]\t%[^\t]%lf", xkey->str, ykey->str, value) : sscanf(buf->str, "%s%s%lf", xkey->str, ykey->str, value) /* WARNING: [xy]key->len have to be set. * we first check sscanf return value */ ; if (cv == 2) *value = 1.0 ; else if (cv != 3) { if (warn || strict) mcxErr ( module , "abc-parser chokes at line %ld [%s]" , (long) xf->lc , buf->str ) ; if (strict) { status = STATUS_FAIL ; break ; } status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP) ; continue ; } else if (!(*value <= FLT_MAX)) /* should catch nan, inf */ *value = 1.0 ; xlen = strlen(xkey->str) ; ylen = strlen(ykey->str) ; xkey->len = xlen ; ykey->len = ylen ; status = iface->statusx = handle_label(&xkey, &(iface->x), iface->map_c, label_cbits | label_dbits, "col") ; if (status == STATUS_FAIL || status == STATUS_IGNORE) break ; status = iface->statusy = handle_label(&ykey, &(iface->y), iface->map_r, label_rbits | label_dbits, "row") ; if (status == STATUS_FAIL || status == STATUS_IGNORE) break ; status = STATUS_OK /* Note: status can never be STATUS_NEW */ ; break ; } while (1) ;if(DEBUG2) fprintf(stderr, "read_abc status %s\n", MCXSTATUS(status)) ; if (status == STATUS_NEW) mcxErr(module, "read_abc panic, because status == STATUS_NEW") /* Below we remove the key from the map if it should be * ignored. It will be freed in the block following this one. */ ; if ( iface->statusx == STATUS_NEW && (iface->statusy == STATUS_FAIL || iface->statusy == STATUS_IGNORE) ) { mcxHashSearch(xkey, iface->map_c->map, MCX_DATUM_DELETE) ; iface->map_c->max_seen-- ; iface->statusx = STATUS_IGNORE ; } else if /* Impossible (given that we break when iface->statusx) but defensive */ ( iface->statusy == STATUS_NEW && (iface->statusx == STATUS_FAIL || iface->statusx == STATUS_IGNORE) ) { mcxHashSearch(ykey, iface->map_r->map, MCX_DATUM_DELETE) ; iface->map_r->max_seen-- ; iface->statusy = STATUS_IGNORE ; } /* NOTE handle_label might have set either to NULL but * that's OK. This is needed because handle_label(&xkey) * might succeed and free xkey (because already present in * map_c->map); then when handle_label(&ykey) fails we need to * clean up. */ ; if (status) { mcxTingFree(&xkey) /* kv deleted if iface->statusx == STATUS_NEW */ ; mcxTingFree(&ykey) /* kv deleted if iface->statusy == STATUS_NEW */ ; } return status ; }
/* Purpose: read a single x/y combination. The x may be cached * due to the etc format, where a single line always refers to the same x * and that x is listed only at the start or line, or omitted with * the etc-ai and 235-ai formats. * * state->x_prev may be used by read_etc in order to obtain the * current x index. */ static mcxstatus read_etc ( mcxIO* xf , stream_state *iface , etc_state *state , double* value ) { mcxbits bits = iface->bits ; FILE* stdbug = stdout ; mcxstatus status = STATUS_OK ; mcxTing* ykey = NULL ; mcxTing* xkey = NULL ; const char* printable ; mcxbool label_cbits = bits & (MCLXIO_STREAM_CTAB_STRICT | MCLXIO_STREAM_CTAB_RESTRICT) ; mcxbool label_rbits = bits & (MCLXIO_STREAM_RTAB_STRICT | MCLXIO_STREAM_RTAB_RESTRICT) ; mcxbool label_dbits = bits & (MCLXIO_STREAM_WARN | MCLXIO_STREAM_DEBUG) ; iface->statusx = STATUS_OK ; iface->statusy = STATUS_OK ; iface->x = state->x_prev ; *value = 1.0 ;if(DEBUG)fprintf(stdbug, "read_etc initially set x to %d\n", (int) iface->x) ; if (!state->etcbuf) state->etcbuf = mcxTingEmpty(NULL, 100) ; do { int n_char_read = 0 ; if (state->etcbuf->len != state->etcbuf_check) { mcxErr ( module , "read_etc sanity check failed %ld %ld" , (long) state->etcbuf->len , (long) state->etcbuf_check ) ; status = STATUS_FAIL ; break ; } /* do we need to read a line ? */ /* -> then set iface->x */ /* fixmefixme: funcify this */ /* iface->x can only be changed in this branch */ /* ************************************************************************** */ if (state->etcbuf_ofs >= state->etcbuf->len) { state->etcbuf_ofs = 0 ; state->n_y = 0 ; if ((status = mcxIOreadLine(xf, state->etcbuf, MCX_READLINE_CHOMP))) break ; state->etcbuf_check = state->etcbuf->len ; if ( !(printable = mcxStrChrAint(state->etcbuf->str, isspace, -1)) || (unsigned char) *printable == '#' ) { state->etcbuf_ofs = state->etcbuf->len ; iface->statusy = STATUS_IGNORE ; break /* fixme: ^ statusx seems to work as well. cleanify design */ ; } ; if (bits & (MCLXIO_STREAM_ETC_AI | MCLXIO_STREAM_235_AI)) { } /* In this branch we do not issue handle_label, so we take care of max_seen. */ else if (bits & MCLXIO_STREAM_235) { if (1 != sscanf(state->etcbuf->str, "%lu%n", &(iface->x), &n_char_read)) { iface->statusx = STATUS_FAIL ; break ; } state->etcbuf_ofs += n_char_read ; if (iface->map_c->max_seen+1 < iface->x+1) /* note mixed-sign comparison */ iface->map_c->max_seen = iface->x ; state->x_prev = iface->x ; } else if (bits & MCLXIO_STREAM_ETC) { xkey = mcxTingEmpty(NULL, state->etcbuf->len) ; if (1 != sscanf(state->etcbuf->str, "%s%n", xkey->str, &n_char_read)) break ; state->etcbuf_ofs += n_char_read ; xkey->len = strlen(xkey->str) ; xkey->str[xkey->len] = '\0' ;if(DEBUG3)fprintf(stderr, "max %lu\n", (ulong) iface->map_c->max_seen) ; iface->statusx = handle_label(&xkey, &(iface->x), iface->map_c, label_cbits | label_dbits, "col") ;if(DEBUG3)fprintf(stderr, "max %lu x %lu\n", (ulong) iface->map_c->max_seen, (ulong) iface->x) ; if (iface->statusx == STATUS_IGNORE || iface->statusx == STATUS_FAIL) { /* iface->x = 141414 recentlyadded */ ;if(DEBUG3)fprintf(stderr, "max %lu\n", (ulong) iface->map_c->max_seen) ; break ; } /* ^ Consider what happens when we break here (x label not * accepted) with map_c->max_seen. Basically x label is * indepedent of y, so we never need to undo the * handle_label action. */ state->x_prev = iface->x ; } else mcxDie(1, module, "strange, really") ; } /* ************************************************************************** */ if ( !( printable = mcxStrChrAint(state->etcbuf->str+state->etcbuf_ofs, isspace, -1) ) || (uchar) *printable == '#' ) { state->etcbuf_ofs = state->etcbuf->len ; /* iface->y = 141414 recentlyadded */ ; iface->statusy = STATUS_IGNORE ; break ; } if (bits & (MCLXIO_STREAM_235_AI | MCLXIO_STREAM_235)) { if (1 != sscanf(state->etcbuf->str+state->etcbuf_ofs, "%lu%n", &(iface->y), &n_char_read)) { char* s = state->etcbuf->str+state->etcbuf_ofs ; while(isspace((uchar) s[0])) s++ ; mcxErr ( module , "unexpected string starting with <%c> on line %lu" , (int) ((uchar) s[0]) , xf->lc ) ; iface->statusy = STATUS_FAIL ; } else { ;if(DEBUG3)fprintf(stdbug, "hit at %d\n", (int) state->etcbuf_ofs); state->etcbuf_ofs += n_char_read ; if (iface->map_r->max_seen+1 < iface->y+1) /* note mixed-sign comparison */ iface->map_r->max_seen = iface->y ; } } else /* ETCANY */ { ykey = mcxTingEmpty(NULL, state->etcbuf->len) ; if (1 != sscanf(state->etcbuf->str+state->etcbuf_ofs, "%s%n", ykey->str, &n_char_read)) break ; ykey->len = strlen(ykey->str) ; ykey->str[ykey->len] = '\0' ; state->etcbuf_ofs += n_char_read ; iface->statusy = handle_label(&ykey, &(iface->y), iface->map_r, label_rbits | label_dbits, "row") ; } /* this won't scale well in terms of organisation if and when * tabs are allowed with 235 mode, because in that case, * with 235-ai and restrict-tabr and extend-tabc we will * need the stuff below duplicated in the 235 branch above. * what happens here is that we only decide now whether * the auto-increment is actually happening. It depends * on there being at least one y that was not rejected. */ ; if ( (bits & (MCLXIO_STREAM_ETC_AI | MCLXIO_STREAM_235_AI)) && (iface->statusy == STATUS_OK || iface->statusy == STATUS_NEW) && !state->n_y ) { iface->x = state->x_prev + 1 /* works first time around */ ; iface->map_c->max_seen = state->x_prev + 1 ; state->n_y++ ; state->x_prev = iface->x ; } ;if(DEBUG2)fprintf(stdbug, "etc handle label we have y %d status %s\n", (int) iface->y, MCXSTATUS(iface->statusy)) ; } while (0) ;if(DEBUG2)fprintf(stdbug, "status %s\n", MCXSTATUS(status)) ; do { if (status) /* e.g. STATUS_DONE (readline) [or STATUS_IGNORE (#)]*/ break /* below iface->statusy == STATUS_NEW should be impossible * given this clause and the code sequence earlier. */ ; if (iface->statusx == STATUS_FAIL || iface->statusx == STATUS_IGNORE) { mcxTingFree(&xkey) ; status = iface->statusx ; break ; } /* case iface->statusx == STATUS_NEW is *always* honored */ ; if (iface->statusy == STATUS_FAIL || iface->statusy == STATUS_IGNORE) { mcxTingFree(&ykey) ; status = iface->statusy ; break ; } } while (0) ; if (status == STATUS_IGNORE || status == STATUS_FAIL) mcxTingFree(&ykey) /* fixme, the action in this branch is done in other places too. cleanify design */ ; if ( iface->statusx == STATUS_IGNORE || !mcxStrChrAint(state->etcbuf->str+state->etcbuf_ofs, isspace, -1) ) state->etcbuf_ofs = state->etcbuf->len ;if(DEBUG3)fprintf ( stdbug, "read_etc %s return x(%s -> %d stat=%s) y(%s -> %d stat=%s) status %s buf %d %d c_max_seen %lu\n" , MCXSTATUS(status) , (xkey ? xkey->str : "-"), (int) iface->x, MCXSTATUS(iface->statusx) , (ykey ? ykey->str : "-"), (int) iface->y, MCXSTATUS(iface->statusy) , MCXSTATUS(status), (int) state->etcbuf->len, (int) state->etcbuf_ofs , (ulong) iface->map_c->max_seen ) ; return status ; }
static dim do_a_file ( aggr** collectpp , const char* fname , dim collect_n ) { mcxIO* xf = mcxIOnew(fname, "r") ; mcxTing* buf = mcxTingEmpty(NULL, 100) ; mcxTing* lbl = mcxTingEmpty(NULL, 100) ; mcxstatus status = STATUS_OK ; aggr* collect = *collectpp ; dim ct = 0, collect_alloc = 0 ; if (!collect_n) collect_alloc = 100 , collect = mcxNAlloc(collect_alloc, sizeof collect[0], NULL, EXIT_ON_FAIL) ; mcxIOopen(xf, EXIT_ON_FAIL) ; while (STATUS_OK == (status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP))) { double val ; const char* tabchar = NULL ; mcxbool get_header = collect_g != 'p' && !ct ? TRUE : FALSE ; mcxTingEnsure(lbl, buf->len) /* if header_g && !ct && !paste create/check label */ /* body of this while loop does too many things, refactor */ ; if (collect_g == 'p' || get_header) { if (!(tabchar = strchr(buf->str, '\t'))) mcxDie(1, me, "paste error at line %d file %s (no tab)", (int) xf->lc, fname) ; mcxTingNWrite(lbl, buf->str, tabchar - buf->str) ; } else { if (2 != sscanf(buf->str, "%s%lg", lbl->str, &val)) mcxDie(1, me, "parse error at line %d file %s", (int) xf->lc, fname) ; lbl->len = strlen(lbl->str) ; } if (!collect_n) { if (ct >= collect_alloc) { dim collect_realloc = collect_alloc * 1.44 ; collect = mcxNRealloc(collect, collect_realloc, collect_alloc, sizeof collect[0], NULL, EXIT_ON_FAIL) ; collect_alloc = collect_realloc ; } collect[ct].label = mcxTingStr(lbl) ; collect[ct].val = collect_g == 'p' || get_header ? 0.0 : val ; collect[ct].columns = collect_g == 'p' || get_header ? mcxTingNew(tabchar + (get_header ? 1 : 0)) : NULL ; } else { if (ct >= collect_n) mcxDie(1, me, "additional lines in file %s", fname) ; if (strcmp(collect[ct].label, lbl->str)) mcxDie ( 1 , me , "label conflict %s/%s at line %d in file %s" , collect[ct].label , lbl->str , (int) xf->lc, fname ) ; if (get_header) /* only need to check identity */ { if (strcmp(tabchar+1, collect[ct].columns->str)) mcxDie(1, me, "different columns <%s> and <%s>", collect[ct].columns->str, tabchar+1) ; } else if (collect_g == 'p') /* tack it on */ mcxTingNAppend(collect[ct].columns, tabchar, buf->len - lbl->len) ; else collect[ct].val += val ; } ct++ ; } if (collect_n) { if (ct != collect_n) mcxDie(1, me, "not enough lines in file %s", fname) ; } else { if (!ct) mcxDie(1, me, "empty file(s)") ; *collectpp = collect ; } mcxIOfree(&xf) ; return ct ; }