示例#1
0
static int cpustr_to_cpulist_scatter(bstring bcpustr, int* cpulist, int length)
{
    topology_init();
    CpuTopology_t cpuid_topology = get_cpuTopology();
    affinity_init();
    AffinityDomains_t affinity = get_affinityDomains();
    char* cpustring = bstr2cstr(bcpustr, '\0');
    if (bstrchrp(bcpustr, ':', 0) != BSTR_ERR)
    {
        int insert = 0;
        int suitidx = 0;
        int* suitable = (int*)malloc(affinity->numberOfAffinityDomains*sizeof(int));
        if (!suitable)
        {
            bcstrfree(cpustring);
            return -ENOMEM;
        }
        for (int i=0; i<affinity->numberOfAffinityDomains; i++)
        {
            if (bstrchrp(affinity->domains[i].tag, cpustring[0], 0) != BSTR_ERR)
            {
                suitable[suitidx] = i;
                suitidx++;
            }
        }
        int* sortedList = (int*) malloc(affinity->domains[suitable[0]].numberOfProcessors * sizeof(int));
        if (!sortedList)
        {
            free(suitable);
            bcstrfree(cpustring);
            return -ENOMEM;
        }
        for (int off=0;off<affinity->domains[suitable[0]].numberOfProcessors;off++)
        {
            for(int i=0;i < suitidx; i++)
            {
                cpulist_sort(affinity->domains[suitable[i]].processorList, sortedList, affinity->domains[suitable[i]].numberOfProcessors);
                cpulist[insert] = sortedList[off];
                insert++;
                if (insert == length)
                    goto scatter_done;
            }
        }
scatter_done:
        bcstrfree(cpustring);
        free(sortedList);
        free(suitable);
        return insert;
    }
    bcstrfree(cpustring);
    return 0;
}
示例#2
0
void hash_file(hash *hashtable[], char *file, unsigned int tablesize)
{
    FILE *fp;
    bstring buffer;
    bstring value;
    int poseq;

    fp = fopen(file, "r");
    if (fp == NULL)
    {
        fp = fopen(file, "w+"); /* create the file */
        if (fp == NULL)
            fprintf(stderr, "Could not create file (%s)\n", file);
        return;
    }

    while ((buffer = bgets((bNgetc) fgetc, fp, '\n')) != NULL)
    {
        /* seriously, wtf is a \10 doing in my buffer you
           c********r? let's get rid of it: */
        poseq = bstrchrp(buffer, '=', 0);
        value = bmidstr(buffer, poseq+1, blength(buffer) - poseq - 2);
        btrunc(buffer, poseq);
        /*printf("%s=%s\n", bdata(buffer), bdata(value));*/
        hash_add(hashtable, buffer, value, tablesize);
    }
    fclose(fp);
    bdestroy(buffer);
    bdestroy(value);
}
示例#3
0
/**
 * Argument:
 * fn - a file name
 * Return:
 * a bstring with a line if successful, NULL otherwise.
 */
bstring alder_file_firstline(const char *fn)
{
    char buf[BUFLEN];
    bstring bline = NULL;
    int len = 0;
    int status = 0;
    int s = alder_file_exist(fn);
    if (s == 0) {
        return 0;
    }
    s = alder_file_isgzip(fn);
    if (s == 1) {
        // open it with zlib.
        gzFile gz = gzopen(fn, "rb");
        if (gz == NULL) return NULL;
        len = gzread(gz, buf, sizeof(buf));
        if (len <= 0) {
            gzclose(gz);
            return NULL;
        }
        if (len <= 0) {
            status = -1;
        }
        gzclose(gz);
    } else {
        // open it with a regular fopen or open.
        FILE *fp = fopen(fn, "rb");
        if (fp == NULL) return NULL;
        len = (int)fread(buf, sizeof(char), BUFLEN, fp);
        if (len <= 0) {
            status = -1;
        }
        fclose(fp);
    }
    if (status == 0) {
        bstring bbuffer = blk2bstr (buf, len);
        int pos = bstrchrp (bbuffer, '\n', 0);
        if (pos == BSTR_ERR) {
            bline = bstrcpy(bbuffer);
        } else {
            bline = bHead(bbuffer, pos);
        }
        bdestroy(bbuffer);
    }
    
    return bline;
}
示例#4
0
void Parse_print_error(const char *message, bstring content, int at, int line_number)
{
    int prev_nl = bstrrchrp(content, '\n', at);
    int next_nl = bstrchrp(content, '\n', at);

    if(prev_nl < 0) {
        log_err("%s AT '%c' on line %d:\n%.*s\n%*s", message,
                bchar(content, at), line_number-1, 
                next_nl, bdata(content),
                at, "^");
    } else {
        log_err("%s AT '%c' on line %d:%.*s\n%*s", message,
                bchar(content, at), line_number, 
                next_nl - prev_nl, bdataofs(content, prev_nl),
                at - prev_nl, "^");
    }
}
static void normalize_space(bstring str) {
	int i=0;
	while(i<blength(str)) {
		int spaceStart = bstrchrp(str,' ',i);
		if (spaceStart == BSTR_ERR)
			break;
		//we found it, now look for the end of this space sequence
		int spaceLen = 1; //exclusive
		while(str->data[spaceStart+spaceLen] == ' ')
			spaceLen++;
		if (spaceLen > 1) {
			//multiple spaces
			bdelete(str,spaceStart+1,spaceLen-1);
		}

		i = spaceStart+1;
	}
}
示例#6
0
/**
 * Argument:
 * fn - file names
 * Return:
 * An ordered file names.
 */
alder_seqid_file_t * alder_seqid_file_init(struct bstrList *fn)
{
    // Test if all of the files exist.
    // Determine the file type (text or gzip).
    // Use the first line to determine file formats (FASTA or FASTQ).
    // Read the first sequence name of each file.
    // Pair files using sequence names.
    alder_seqid_file_t *v = malloc(sizeof(alder_seqid_file_t));
    int numberOfFile = fn->qty;
    v->filename = bstrVectorCreate(numberOfFile);
    v->type = malloc(numberOfFile * sizeof(int));
    v->format = malloc(numberOfFile * sizeof(int));
    v->pair = malloc(numberOfFile * sizeof(int));
    
    for (int i = 0; i < fn->qty; i++) {
        int s = alder_file_exist(bdata(fn->entry[i]));
        if (s == 0) {
            alder_seqid_file_free(v);
            return NULL;
        }
    }
    for (int i = 0; i < fn->qty; i++) {
        int s = alder_file_isgzip(bdata(fn->entry[i]));
        if (s == 1) {
            v->type[i] = 2;
        } else {
            v->type[i] = 1;
        }
    }
    for (int i = 0; i < fn->qty; i++) {
        int s = alder_file_whatformat(bdata(fn->entry[i]));
        if (s == 1) {
            v->format[i] = 1;
        } else if (s == 2) {
            v->format[i] = 2;
        } else {
            alder_seqid_file_free(v);
            return NULL;
        }
    }
    
    struct bstrList *bnames = bstrVectorCreate(fn->qty);
    for (int i = 0; i < fn->qty; i++) {
        bstring s = alder_file_firstline(bdata(fn->entry[i]));
        int posFirstSpace = bstrchrp(s, ' ', 0);
        bstring bword = NULL;
        if (posFirstSpace != BSTR_ERR) {
            bword = bHead(s, posFirstSpace);
        } else {
            bword = bstrcpy(s);
        }
        bdestroy(s);
        bstring bname = bTail(bword, bword->slen - 1);
        bdestroy(bword);
        bstrVectorAdd(bnames, bdata(bname));
        bdestroy(bname);
    }
    
    for (int i = 0; i < fn->qty; i++) {
        v->pair[i] = -1;
        for (int j = 0; j < fn->qty; j++) {
            if (i == j) continue;
            if (!bstrcmp(bnames->entry[i], bnames->entry[j])) {
                v->pair[i] = j;
            }
        }
    }
    
    int *pairCount = malloc(numberOfFile * sizeof(int));
    memset(pairCount, 0, numberOfFile*sizeof(int));
    for (int i = 0; i < fn->qty; i++) {
        int j = v->pair[i];
        pairCount[j]++;
    }
    
    for (int i = 0; i < fn->qty; i++) {
        if (pairCount[i] > 1) {
            free(pairCount);
            alder_seqid_file_free(v);
            return NULL;
        }
    }
    free(pairCount);
    
    ///////////////////////////////////////////////////////////////////////////
    // Order pairs.
    int pairI = 0;
    alder_vector_pair_t * pair = alder_vector_pair_t_alloc(fn->qty);
    for (int i = 0; i < fn->qty; i++) {
        if (v->pair[i] >= 0) {
            int alreadPaired = 0;
            for (int j = 0; j < pairI; j++) {
                if (pair->data[j].first == i ||
                    pair->data[j].second== i) {
                    alreadPaired = 1;
                    break;
                }
            }
            if (alreadPaired == 0) {
                if (i < v->pair[i]) {
                    pair->data[pairI].first = i;
                    pair->data[pairI].second= v->pair[i];
                } else {
                    pair->data[pairI].first = v->pair[i];
                    pair->data[pairI].second= i;
                }
                pairI++;
            }
        }
    }
    for (int i = 0; i < fn->qty; i++) {
        if (v->pair[i] < 0) {
            pair->data[pairI].first = i;
            pair->data[pairI].second= -1;
            pairI++;
        }
    }
    alder_seqid_file_t *v2 = malloc(sizeof(alder_seqid_file_t));
    v2->filename = bstrVectorCreate(numberOfFile);
    v2->type = malloc(numberOfFile * sizeof(int));
    v2->format = malloc(numberOfFile * sizeof(int));
    v2->pair = malloc(numberOfFile * sizeof(int));
    int seqidIndex = 0;
    for (int i = 0; i < pairI; i++) {
        int first = pair->data[i].first;
        int second = pair->data[i].second;
        assert(first >= 0);
        bstrVectorAdd(v2->filename, bdata(fn->entry[first]));
        v2->type[seqidIndex] = v->type[first];
        v2->format[seqidIndex] = v->format[first];
        
        if (second >= 0) {
            v2->pair[seqidIndex] = seqidIndex + 1;
        } else {
            v2->pair[seqidIndex] = -1;
        }
        seqidIndex++;
        if (second >= 0) {
            bstrVectorAdd(v2->filename, bdata(fn->entry[second]));
            v2->type[seqidIndex] = v->type[second];
            v2->format[seqidIndex] = v->format[second];
            v2->pair[seqidIndex] = seqidIndex - 1;
            seqidIndex++;
        }
    }
    assert(seqidIndex == numberOfFile);
    
#if 0
    for (int i = 0; i < fn->qty; i++) {
        int j = v->pair[i];
        if (j < 0) {
            fprintf(stdout, "%2d %10s: %10s (%d) - no pair (%d)\n", i,
                    bdata(fn->entry[i]),
                    bdata(bnames->entry[i]), pairCount[i], j);
        } else {
            fprintf(stdout, "%2d %10s: %10s (%d) - pair %10s (%d)\n", i,
                    bdata(fn->entry[i]),
                    bdata(bnames->entry[i]), pairCount[i], bdata(fn->entry[j]), j);
        }
    }
    
    fprintf(stdout, "\n");
    for (int i = 0; i < fn->qty; i++) {
        fprintf(stdout, "%2d %10s: format (%d), type (%d), pair (%d)\n", i,
                bdata(v2->filename->entry[i]),
                v2->format[i], v2->type[i], v2->pair[i]);
    }
#endif
    
    alder_seqid_file_free(v);
    alder_vector_pair_t_free(pair);
    bstrVectorDelete(bnames);
    return v2;
}
示例#7
0
int cpustr_to_cpulist(char* cpustring, int* cpulist, int length)
{
    int insert = 0;
    int len = 0;
    int ret = 0;
    bstring bcpustr = bfromcstr(cpustring);
    struct bstrList* strlist = bstrListCreate();
    bstring scattercheck = bformat("scatter");
    topology_init();
    CpuTopology_t cpuid_topology = get_cpuTopology();
    strlist = bsplit(bcpustr, '@');

    int* tmpList = (int*)malloc(length * sizeof(int));
    if (tmpList == NULL)
    {
        bstrListDestroy(strlist);
        bdestroy(scattercheck);
        bdestroy(bcpustr);
        return -ENOMEM;
    }
    for (int i=0; i< strlist->qty; i++)
    {
        if (binstr(strlist->entry[i], 0, scattercheck) != BSTR_ERR)
        {
            ret = cpustr_to_cpulist_scatter(strlist->entry[i], tmpList, length);
            insert += cpulist_concat(cpulist, insert, tmpList, ret);
        }
        else if (bstrchrp(strlist->entry[i], 'E', 0) == 0)
        {
            ret = cpustr_to_cpulist_expression(strlist->entry[i], tmpList, length);
            insert += cpulist_concat(cpulist, insert, tmpList, ret);
        }
        else if (bstrchrp(strlist->entry[i], 'L', 0) == 0)
        {
            ret = cpustr_to_cpulist_logical(strlist->entry[i], tmpList, length);
            insert += cpulist_concat(cpulist, insert, tmpList, ret);
        }
        else if (cpuid_topology->activeHWThreads < cpuid_topology->numHWThreads)
        {
            fprintf(stdout, "INFO: You are running LIKWID in a cpuset with %d CPUs, only logical numbering allowed\n", cpuid_topology->activeHWThreads);
            if (((bstrchrp(strlist->entry[i], 'N', 0) == 0) ||
                (bstrchrp(strlist->entry[i], 'S', 0) == 0) ||
                (bstrchrp(strlist->entry[i], 'C', 0) == 0) ||
                (bstrchrp(strlist->entry[i], 'M', 0) == 0)) &&
                (bstrchrp(strlist->entry[i], ':', 0) != BSTR_ERR))
            {
                bstring newstr = bformat("L:");
                bconcat(newstr, strlist->entry[i]);
                ret = cpustr_to_cpulist_logical(newstr, tmpList, length);
                insert += cpulist_concat(cpulist, insert, tmpList, ret);
                bdestroy(newstr);
            }
            else
            {
                bstring newstr = bformat("L:N:");
                bconcat(newstr, strlist->entry[i]);
                ret = cpustr_to_cpulist_logical(newstr, tmpList, length);
                insert += cpulist_concat(cpulist, insert, tmpList, ret);
                bdestroy(newstr);
            }
        }
        else if (((bstrchrp(strlist->entry[i], 'N', 0) == 0) ||
            (bstrchrp(strlist->entry[i], 'S', 0) == 0) ||
            (bstrchrp(strlist->entry[i], 'C', 0) == 0) ||
            (bstrchrp(strlist->entry[i], 'M', 0) == 0)) &&
            (bstrchrp(strlist->entry[i], ':', 0) != BSTR_ERR))
        {
            bstring newstr = bformat("L:");
            bconcat(newstr, strlist->entry[i]);
            ret = cpustr_to_cpulist_logical(newstr, tmpList, length);
            insert += cpulist_concat(cpulist, insert, tmpList, ret);
            bdestroy(newstr);
        }

        else
        {
            ret = cpustr_to_cpulist_physical(strlist->entry[i], tmpList, length);
            insert += cpulist_concat(cpulist, insert, tmpList, ret);
        }
    }
    free(tmpList);
    bstrListDestroy(strlist);
    return insert;
}
示例#8
0
static int cpustr_to_cpulist_physical(bstring bcpustr, int* cpulist, int length)
{
    topology_init();
    CpuTopology_t cpuid_topology = get_cpuTopology();
    affinity_init();
    AffinityDomains_t affinity = get_affinityDomains();
    bstring bdomain;
    bstring blist;
    int domainidx = -1;
    if (bstrchrp(bcpustr, ':', 0) != BSTR_ERR)
    {
        struct bstrList* strlist = bstrListCreate();
        strlist = bsplit(bcpustr, ':');
        bdomain = bstrcpy(strlist->entry[0]);
        blist = bstrcpy(strlist->entry[1]);
        bstrListDestroy(strlist);
    }
    else
    {
        bdomain = bformat("N");
        blist = bstrcpy(bcpustr);
    }
    for (int i=0; i<affinity->numberOfAffinityDomains; i++)
    {
        if (bstrcmp(bdomain, affinity->domains[i].tag) == 0)
        {
            domainidx = i;
            break;
        }
    }
    if (domainidx < 0)
    {
        fprintf(stderr, "Cannot find domain %s\n", bdata(bdomain));
        bdestroy(bdomain);
        bdestroy(blist);
        return 0;
    }
    struct bstrList* strlist = bstrListCreate();
    strlist = bsplit(blist, ',');
    int insert = 0;
    for (int i=0;i< strlist->qty; i++)
    {
        if (bstrchrp(strlist->entry[i], '-', 0) != BSTR_ERR)
        {
            struct bstrList* indexlist = bstrListCreate();
            indexlist = bsplit(strlist->entry[i], '-');
            if (atoi(bdata(indexlist->entry[0])) <= atoi(bdata(indexlist->entry[1])))
            {
                for (int j=atoi(bdata(indexlist->entry[0])); j<=atoi(bdata(indexlist->entry[1]));j++)
                {
                    if (cpu_in_domain(domainidx, j))
                    {
                        cpulist[insert] = j;
                        insert++;
                        if (insert == length)
                        {
                            bstrListDestroy(indexlist);
                            goto physical_done;
                        }
                    }
                    else
                    {
                        fprintf(stderr, "CPU %d not in domain %s\n", j, bdata(affinity->domains[domainidx].tag));
                    }
                }
            }
            else
            {
                for (int j=atoi(bdata(indexlist->entry[0])); j>=atoi(bdata(indexlist->entry[1]));j--)
                {
                    if (cpu_in_domain(domainidx, j))
                    {
                        cpulist[insert] = j;
                        insert++;
                        if (insert == length)
                        {
                            bstrListDestroy(indexlist);
                            goto physical_done;
                        }
                    }
                    else
                    {
                        fprintf(stderr, "CPU %d not in domain %s\n", j, bdata(affinity->domains[domainidx].tag));
                    }
                }
            }
            bstrListDestroy(indexlist);
        }
        else
        {
            int cpu = atoi(bdata(strlist->entry[i]));
            if (cpu_in_domain(domainidx, cpu))
            {
                cpulist[insert] = cpu;
                insert++;
                if (insert == length)
                {
                    goto physical_done;
                }
            }
            else
            {
                fprintf(stderr, "CPU %d not in domain %s\n", cpu, bdata(affinity->domains[domainidx].tag));
            }
        }
    }
physical_done:
    bstrListDestroy(strlist);
    bdestroy(bdomain);
    bdestroy(blist);
    return insert;
}
示例#9
0
static int cpustr_to_cpulist_logical(bstring bcpustr, int* cpulist, int length)
{
    topology_init();
    CpuTopology_t cpuid_topology = get_cpuTopology();
    affinity_init();
    AffinityDomains_t affinity = get_affinityDomains();
    int domainidx = -1;
    bstring bdomain;
    bstring blist;
    if (bstrchrp(bcpustr, 'L', 0) != 0)
    {
        fprintf(stderr, "Not a valid CPU expression\n");
        return 0;
    }
    struct bstrList* strlist = bstrListCreate();
    strlist = bsplit(bcpustr, ':');
    if (strlist->qty != 3)
    {
        fprintf(stderr, "ERROR: Invalid expression, should look like L:<domain>:<indexlist> or be in a cpuset\n");
        bstrListDestroy(strlist);
        return 0;
    }
    bdomain = bstrcpy(strlist->entry[1]);
    blist = bstrcpy(strlist->entry[2]);
    bstrListDestroy(strlist);
    for (int i=0; i<affinity->numberOfAffinityDomains; i++)
    {
        if (bstrcmp(bdomain, affinity->domains[i].tag) == 0)
        {
            domainidx = i;
            break;
        }
    }
    if (domainidx < 0)
    {
        fprintf(stderr, "Cannot find domain %s\n", bdata(bdomain));
        return 0;
    }
    int *inlist = malloc(affinity->domains[domainidx].numberOfProcessors * sizeof(int));
    if (inlist == NULL)
    {
        return -ENOMEM;
    }
    int ret = cpulist_sort(affinity->domains[domainidx].processorList, inlist, affinity->domains[domainidx].numberOfProcessors);

    strlist = bstrListCreate();
    strlist = bsplit(blist, ',');
    int insert = 0;
    for (int i=0; i< strlist->qty; i++)
    {
        if (bstrchrp(strlist->entry[i], '-', 0) != BSTR_ERR)
        {
            struct bstrList* indexlist = bstrListCreate();
            indexlist = bsplit(strlist->entry[i], '-');
            if (atoi(bdata(indexlist->entry[0])) <= atoi(bdata(indexlist->entry[1])))
            {
                for (int j=atoi(bdata(indexlist->entry[0])); j<=atoi(bdata(indexlist->entry[1]));j++)
                {
                    cpulist[insert] = inlist[j];
                    insert++;
                    if (insert == length)
                    {
                        bstrListDestroy(indexlist);
                        goto logical_done;
                    }
                }
            }
            else
            {
                for (int j=atoi(bdata(indexlist->entry[0])); j>=atoi(bdata(indexlist->entry[1]));j--)
                {
                    cpulist[insert] = inlist[j];
                    insert++;
                    if (insert == length)
                    {
                        bstrListDestroy(indexlist);
                        goto logical_done;
                    }
                }
            }
            bstrListDestroy(indexlist);
        }
        else
        {
            cpulist[insert] = inlist[atoi(bdata(strlist->entry[i]))];
            insert++;
            if (insert == length)
            {
                goto logical_done;
            }
        }
    }
logical_done:
    free(inlist);
    bstrListDestroy(strlist);
    return insert;
}
示例#10
0
static int cpustr_to_cpulist_expression(bstring bcpustr, int* cpulist, int length)
{
    topology_init();
    CpuTopology_t cpuid_topology = get_cpuTopology();
    affinity_init();
    AffinityDomains_t affinity = get_affinityDomains();
    bstring bdomain;
    int domainidx = -1;
    int count = 0;
    int stride = 0;
    int chunk = 0;
    if (bstrchrp(bcpustr, 'E', 0) != 0)
    {
        fprintf(stderr, "Not a valid CPU expression\n");
        return 0;
    }
    struct bstrList* strlist = bstrListCreate();
    strlist = bsplit(bcpustr, ':');
    if (strlist->qty == 3)
    {
        bdomain = bstrcpy(strlist->entry[1]);
        count = atoi(bdata(strlist->entry[2]));
        stride = 1;
        chunk = 1;
    }
    else if (strlist->qty == 5)
    {
        bdomain = bstrcpy(strlist->entry[1]);
        count = atoi(bdata(strlist->entry[2]));
        chunk = atoi(bdata(strlist->entry[3]));
        stride = atoi(bdata(strlist->entry[4]));
    }
    for (int i=0; i<affinity->numberOfAffinityDomains; i++)
    {
        if (bstrcmp(bdomain, affinity->domains[i].tag) == 0)
        {
            domainidx = i;
            break;
        }
    }
    if (domainidx < 0)
    {
        fprintf(stderr, "Cannot find domain %s\n", bdata(bdomain));
        bstrListDestroy(strlist);
        return 0;
    }
    int offset = 0;
    int insert = 0;
    for (int i=0;i<count;i++)
    {
        for (int j=0;j<chunk && offset+j<affinity->domains[domainidx].numberOfProcessors;j++)
        {
            cpulist[insert] = affinity->domains[domainidx].processorList[offset + j];
            insert++;
            if (insert == length)
                goto expression_done;
        }
        offset += stride;
        if (offset >= affinity->domains[domainidx].numberOfProcessors)
        {
            offset = 0;
        }
        if (insert >= count)
            goto expression_done;
    }
    bstrListDestroy(strlist);
    return 0;
expression_done:
    bstrListDestroy(strlist);
    return insert;
}
示例#11
0
static int
parse_server_xport_option(allium_ptcfg *cfg, const bstring arg_str)
{
	struct allium_ptcfg_method_s *m;
	struct allium_ptcfg_xport_opt_s *opt;
	bstring transport;
	bstring key;
	bstring value;
	int i, j;

	assert(cfg);
	assert(arg_str);

	if (0 == blength(arg_str))
		return (-1);

	/*
	 * Figure out what transport this argument is for.  We don't need to
	 * unescape method names as they conform to "[a-zA-Z_][a-zA-Z0-9_]*"
	 */
	i = bstrchr(arg_str, ':');
	if (BSTR_ERR == i)
		return (-1);

	transport = bmidstr(arg_str, 0, i);
	if (NULL == transport)
		return (-1);

	m = get_method(cfg, bdata(transport));
	bdestroy(transport);    /* Done with the transport at this point */
	if (NULL == m)
		return (-1);

	/*
	 * Figure out what key the transport is expecting the value for.
	 *
	 * XXX: If people want to use the escaped characters in their keys they
	 * get what they deserve (Note this as a gotcha and fix it when people
	 * cry about it).
	 */
	j = bstrchrp(arg_str, '=', i);
	if (BSTR_ERR == j)
		return (-1);

	key = bmidstr(arg_str, i + 1, j - i - 1);
	if (NULL == key)
		return (-1);

	opt = get_xport_opt(m, key);
	if ((NULL != opt) || (0 == blength(key))) {
		/* We don't support redefining existing key/value pairs */
		bdestroy(key);
		return (-1);
	}

	/* Parse the value, unescaping as needed */
	value = bmidstr(arg_str, j + 1, blength(arg_str) - j - 1);
	if (NULL == value) {
		bdestroy(key);
		return (-1);
	}
	unescape_opt_value(value);

	/* Stash it away so people can get to it */
	opt = calloc(1, sizeof(*opt));
	if (NULL == opt) {
		bdestroy(key);
		bdestroy_safe(value);
		return (-1);
	}
	opt->key = key;
	opt->value = value;
	opt->next = m->xport_opts;
	m->xport_opts = opt;

	return (0);
}