ofs mcxIOappendChunk ( mcxIO *xf , mcxTing *dst , dim sz , mcxbits flags cpl__unused ) { unsigned long psz = getpagesize() ; dim k = sz / psz /* fixme: size checks? */ ; dim rem = sz % psz ; ofs r = 1 /* pretend in case k == 0 */ /* mcxbool account = flags & MCX_CHUNK_ACCOUNT ? TRUE : FALSE */ ; dim offset = dst->len ; char* p ; if (!dst || !xf->fp || !mcxTingEnsure(dst, dst->len + sz)) return -1 /* fixme set some (new) errno */ ; if (k) while (k-- > 0 && (r = read(fileno(xf->fp), dst->str+dst->len, psz)) > 0) dst->len += r /* careful with unsignedness */ /* ^ Note: fileno is POSIX, not c99 */ ; if ( r > 0 && rem > 0 && (r = read(fileno(xf->fp), dst->str+dst->len, rem)) > 0 ) dst->len += r ; dst->str[dst->len] = '\0' ; xf->bc += dst->len - offset ; for (p = dst->str+offset; p<dst->str+dst->len; p++) { if (*p == '\n') { xf->lc++ ; xf->lo_ = xf->lo ; xf->lo = 0 ; } else xf->lo++ ; } /* fixme; what if k == 0, rem == 0 ? */ if (!r) /* fixme; other possibilities? */ xf->ateof = 1 ; return dst->len ; }
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 ; }
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 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 ; }