Beispiel #1
0
HashTable *load_map(char *fn) {
    HashTable *h = HashTableCreate(65536, HASH_DYNAMIC_SIZE | HASH_POOL_ITEMS);
    FILE *fp;
    char line[8192];

    if (NULL == (fp = fopen(fn, "r"))) {
	perror(fn);
	return NULL;
    }

    while(fgets(line, 8192, fp)) {
	char *cp, *from, *to;
	HashData hd;

	for (from = cp = line; *cp && !isspace(*cp); cp++);
	if (!*cp) {
	    fprintf(stderr, "Malformed line '%s'\n", line);
	    return NULL;
	}
	*cp++ = 0;
	
	for (to = cp; isprint(*cp); cp++);
	*cp++ = 0;

	hd.p = strdup(to);
	if (!HashTableAdd(h, from, strlen(from), hd, NULL))
	    return NULL;
    }

    close(fp);

    return h;
}
Beispiel #2
0
static int HashTableTestFull02 (void)
{
    int result = 0;
    HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL);
    if (ht == NULL)
        goto end;

    int r = HashTableAdd(ht, "test", 4);
    if (r != 0)
        goto end;

    char *rp = HashTableLookup(ht, "test", 4);
    if (rp == NULL)
        goto end;

    r = HashTableRemove(ht, "test2", 5);
    if (r == 0)
        goto end;

    /* all is good! */
    result = 1;
end:
    if (ht != NULL) HashTableFree(ht);
    return result;
}
/**
 * \brief Parses a line from the reference config file and adds it to Reference
 *        Config hash table DetectEngineCtx->reference_conf_ht.
 *
 * \param rawstr Pointer to the string to be parsed.
 * \param de_ctx Pointer to the Detection Engine Context.
 *
 * \retval  0 On success.
 * \retval -1 On failure.
 */
static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx)
{
    char system[64];
    char url[1024];

    SCRConfReference *ref_new = NULL;
    SCRConfReference *ref_lookup = NULL;

#define MAX_SUBSTRINGS 30
    int ret = 0;
    int ov[MAX_SUBSTRINGS];

    ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30);
    if (ret < 0) {
        SCLogError(SC_ERR_REFERENCE_CONFIG, "Invalid Reference Config in "
                   "reference.config file");
        goto error;
    }

    /* retrieve the reference system */
    ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, system, sizeof(system));
    if (ret < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring() failed");
        goto error;
    }

    /* retrieve the reference url */
    ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, url, sizeof(url));
    if (ret < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring() failed");
        goto error;
    }

    /* Create a new instance of the parsed Reference string */
    ref_new = SCRConfAllocSCRConfReference(system, url);
    if (ref_new == NULL)
        goto error;

    /* Check if the Reference is present in the HashTable.  In case it's present
     * ignore it, as it's a duplicate.  If not present, add it to the table */
    ref_lookup = HashTableLookup(de_ctx->reference_conf_ht, ref_new, 0);
    if (ref_lookup == NULL) {
        if (HashTableAdd(de_ctx->reference_conf_ht, ref_new, 0) < 0) {
            SCLogDebug("HashTable Add failed");
        }
    } else {
        SCLogDebug("Duplicate reference found inside reference.config");
        SCRConfDeAllocSCRConfReference(ref_new);
    }

    return 0;

 error:
    return -1;
}
Beispiel #4
0
/*
 * Removes some or all tags from some or all contigs.
 * If the contig list or tag list is blank it implies all contigs or all tags.
 *
 * Returns 0 on success
 *        -1 on failure
 */
int delete_tags(GapIO *io, int ncontigs, contig_list_t *contigs,
		char *tag_list, int verbose) {
    HashTable *h = NULL;
    int ret = 0;

    /* Hash tag types */
    if (tag_list && *tag_list) {
	int i;
	if (SetActiveTags(tag_list) == -1) {
	    return -1;
	}
	h = HashTableCreate(32, 0);
	for (i = 0; i < number_of_active_tags; i++) {
	    HashData hd;
	    hd.i = 0;
	    HashTableAdd(h, active_tag_types[i], 4, hd, NULL);
	}
    }

    /* Iterate over contig list or all contigs */
    if (verbose)
	vfuncheader("Delete Tags");

    if (ncontigs) {
	int i;

	for (i = 0; i < ncontigs; i++) {
	    contig_t *c = cache_search(io, GT_Contig, contigs[i].contig);
	    vmessage("Scanning contig %d of %d (%s)\n",
		     i+1, ncontigs, c->name);
	    ret |= delete_tag_single_contig(io, contigs[i].contig, h, verbose);
	    UpdateTextOutput();
	    cache_flush(io);
	}

    } else {
	int i;
	tg_rec *order = ArrayBase(tg_rec, io->contig_order);

	for (i = 0; i < NumContigs(io); i++) {
	    contig_t *c = cache_search(io, GT_Contig, order[i]);
	    vmessage("Scanning contig %d of %d (%s)\n",
		     i+1, NumContigs(io), c->name);
	    ret |= delete_tag_single_contig(io, order[i], h, verbose);
	    UpdateTextOutput();
	    cache_flush(io);
	}
    }

    SetActiveTags("");
    if (h)
	HashTableDestroy(h, 0);

    return ret;
}
Beispiel #5
0
HashTable *readSnpFile(char *snp_file)
{
    FILE *fp;
    HashTable *snp_hash;
    static const int line_size = 8192;
    char line[line_size];
    size_t count = 0;
    char last_chrom[100] = "";

    display("reading snp file %s\n", snp_file);

    fp = fopen(snp_file, "rb");
    if (NULL == fp) {
        die("ERROR: can't open known snp file %s: %s\n", snp_file, strerror(errno));
    }

    if (NULL == (snp_hash = HashTableCreate(0, HASH_DYNAMIC_SIZE | HASH_FUNC_JENKINS3))) {
        die("ERROR: creating snp hash table\n");
    }

    while (fgets(line, line_size, fp)) {
        char key[100];
        HashData hd;
        int bin, start, end;
        char chrom[100];

        if (4 != sscanf(line, "%d\t%s\t%d\t%d", &bin, chrom, &start, &end)) {
            die("ERROR: reading snp file\n%s\n", line);
        }

        /* N.B rod start is 0 based */
        snprintf(key, sizeof(key), "%s:%d", chrom, start);
        hd.i = 0;
        if (NULL == HashTableAdd(snp_hash, key, strlen(key), hd, NULL)) {
            die("ERROR: building snp hash table\n");
        }

        if (strcmp(chrom, last_chrom)) {
            strcpy(last_chrom, chrom);
            count = 0;
        }

        count++;
    }

    fclose(fp);

	return snp_hash;
}
Beispiel #6
0
static int HashTableTestAdd02 (void) {
    int result = 0;
    HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL);
    if (ht == NULL)
        goto end;

    int r = HashTableAdd(ht, NULL, 4);
    if (r == 0)
        goto end;

    /* all is good! */
    result = 1;
end:
    if (ht != NULL) HashTableFree(ht);
    return result;
}
Beispiel #7
0
void construct_hash(HashFile *hf) {
    int i;

    for (i = 0; i < nfiles; i++) {
	HashData hd;
	HashFileItem *hfi = (HashFileItem *)calloc(1, sizeof(*hfi));

	/* Just use the last head/foot defined as we only allow 1 at the mo. */
	hfi->header  = hf->nheaders;
	hfi->footer  = hf->nfooters;
	hfi->pos     = files[i].pos;
	hfi->size    = files[i].size;
	hfi->archive = files[i].archive;
	hd.p = hfi;
	HashTableAdd(hf->h, files[i].member, strlen(files[i].member),
		     hd, NULL);
    }
}
Beispiel #8
0
void cram_stats_add(cram_stats *st, int32_t val) {
    st->nsamp++;

    //assert(val >= 0);

    if (val < MAX_STAT_VAL && val >= 0) {
	st->freqs[val]++;
    } else {
	HashItem *hi;

	if (!st->h) {
	    st->h = HashTableCreate(2048, HASH_DYNAMIC_SIZE|HASH_NONVOLATILE_KEYS|HASH_INT_KEYS);
	}

	if ((hi = HashTableSearch(st->h, (char *)(size_t)val, 4))) {
	    hi->data.i++;
	} else {
	    HashData hd;
	    hd.i = 1;
	    HashTableAdd(st->h, (char *)(size_t)val, 4, hd, NULL);
	}
    }
}
Beispiel #9
0
/*
 * process one BAM record, and store accumulated results in 'results'
 */
int seqchksum_processRecord(bam1_t *rec, HASH_TYPE hash, chksum_results_t *results)
{
    uint32_t crc = 0;

    uint16_t aflags = rec->core.flag;
    uint8_t *seq = get_read(rec);
    uint8_t *qual = get_quality(rec);
    uint16_t flag_mask = BAM_FPAIRED | BAM_FREAD1 | BAM_FREAD2;
    uint8_t flags = (aflags & flag_mask) & 0xFF;
    bool pass = !(aflags & BAM_FQCFAIL);;
    char *qname = bam_get_qname(rec);
    uint8_t *tag;
    char *rgid;
    HashItem *hi;
    HashData hd;
    int newitem;
    digest_line_t *dline_all;
    digest_line_t *dline;

    // look up the RG tag
    tag = bam_aux_get(rec, "RG");
    //hd.p = malloc(sizeof(digest_line_t));
    if (tag) rgid = bam_aux2Z(tag);
    else     rgid = "";

    hd.p = NULL;
    hi = HashTableAdd(results->rgHash, rgid, 0, hd, &newitem);
    if (newitem) {
        hi->data.p = malloc(sizeof(digest_line_t));
        dline = hi->data.p;
        init_digest_line(hash,dline);
    } else {
        dline = hi->data.p;
    }

    dline_all = &(results->all);

    // flags + sequence chksum
    update_crc(&crc,&flags,1);
    update_crc(&crc,seq,strlen((char*)seq));

    update_digest_line(hash, pass, dline, crc, 0);
    update_digest_line(hash, pass, dline_all, crc, 0);

    // flags + sequence + quality chksum (don't reset crc, just add quality)
    update_crc(&crc,qual,strlen((char*)qual));
    update_digest_line(hash, pass, dline, crc, 2);
    update_digest_line(hash, pass, dline_all, crc, 2);

    // name + flags + sequence chksum
    crc = 0;
    update_crc(&crc, (uint8_t *)qname, strlen(qname)+1);
    update_crc(&crc, &flags, 1);
    update_crc(&crc,seq,strlen((char*)seq));
    update_digest_line(hash, pass, dline, crc, 1);
    update_digest_line(hash, pass, dline_all, crc, 1);

    // flags + sequence + tags chksum
    crc = 0;
    update_crc(&crc, &flags, 1);
    update_crc(&crc,seq,strlen((char*)seq));
    tag = bam_aux_get(rec,"BC"); if (tag) update_crc(&crc,tag-2,aux_type2size(tag)+3);
    tag = bam_aux_get(rec,"FI"); if (tag) update_crc(&crc,tag-2,aux_type2size(tag)+3);
    tag = bam_aux_get(rec,"QT"); if (tag) update_crc(&crc,tag-2,aux_type2size(tag)+3);
    tag = bam_aux_get(rec,"RT"); if (tag) update_crc(&crc,tag-2,aux_type2size(tag)+3);
    tag = bam_aux_get(rec,"TC"); if (tag) update_crc(&crc,tag-2,aux_type2size(tag)+3);
    update_digest_line(hash, pass, dline, crc, 3);
    update_digest_line(hash, pass, dline_all, crc, 3);

    free(seq); free(qual);
    return 0;
}
Beispiel #10
0
static NTSTATUS
GnttabMapForeignPages(
    IN  PINTERFACE              Interface,
    IN  USHORT                  Domain,
    IN  ULONG                   NumberPages,
    IN  PULONG                  References,
    IN  BOOLEAN                 ReadOnly,
    OUT PHYSICAL_ADDRESS        *Address
    )
{
    PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
    LONG                        PageIndex;
    PHYSICAL_ADDRESS            PageAddress;
    PXENBUS_GNTTAB_MAP_ENTRY    MapEntry;
    NTSTATUS                    status;

    status = FdoAllocateIoSpace(Context->Fdo,
                                NumberPages * PAGE_SIZE,
                                Address);
    if (!NT_SUCCESS(status))
        goto fail1;

    MapEntry = __GnttabAllocate(FIELD_OFFSET(XENBUS_GNTTAB_MAP_ENTRY,
                                             MapHandles) +
                                (NumberPages * sizeof (ULONG)));

    status = STATUS_NO_MEMORY;
    if (MapEntry == NULL)
        goto fail2;

    PageAddress.QuadPart = Address->QuadPart;
    MapEntry->NumberPages = NumberPages;

    for (PageIndex = 0; PageIndex < (LONG)NumberPages; PageIndex++) {
        status = GrantTableMapForeignPage(Domain,
                                          References[PageIndex],
                                          PageAddress,
                                          ReadOnly,
                                          &MapEntry->MapHandles[PageIndex]);
        if (!NT_SUCCESS(status))
            goto fail3;

        PageAddress.QuadPart += PAGE_SIZE;
    }

    status = HashTableAdd(Context->MapTable,
                          (ULONG_PTR)Address->QuadPart,
                          (ULONG_PTR)MapEntry);
    if (!NT_SUCCESS(status))
        goto fail4;

    return STATUS_SUCCESS;

fail4:
    Error("fail4\n");

fail3:
    Error("fail3\n");

    while (--PageIndex >= 0) {
        PageAddress.QuadPart -= PAGE_SIZE;
        (VOID) GrantTableUnmapForeignPage(MapEntry->MapHandles[PageIndex],
                                          PageAddress);
    }

    __GnttabFree(MapEntry);

fail2:
    Error("fail2\n");

    FdoFreeIoSpace(Context->Fdo, *Address, NumberPages * PAGE_SIZE);

fail1:
    Error("fail1: (%08x)\n", status);

    return status;
}
/**
 * \brief Parses a line from the classification file and adds it to Classtype
 *        hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_conf_ht.
 *
 * \param rawstr Pointer to the string to be parsed.
 * \param index  Relative index of the string to be parsed.
 * \param de_ctx Pointer to the Detection Engine Context.
 *
 * \retval  0 On success.
 * \retval -1 On failure.
 */
int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx)
{
    const char *ct_name = NULL;
    const char *ct_desc = NULL;
    const char *ct_priority_str = NULL;
    int ct_priority = 0;
    uint8_t ct_id = index;

    SCClassConfClasstype *ct_new = NULL;
    SCClassConfClasstype *ct_lookup = NULL;

#define MAX_SUBSTRINGS 30
    int ret = 0;
    int ov[MAX_SUBSTRINGS];

    ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30);
    if (ret < 0) {
        SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid Classtype in "
                   "classification.config file");
        goto error;
    }

    /* retrieve the classtype name */
    ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name);
    if (ret < 0) {
        SCLogInfo("pcre_get_substring() failed");
        goto error;
    }

    /* retrieve the classtype description */
    ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc);
    if (ret < 0) {
        SCLogInfo("pcre_get_substring() failed");
        goto error;
    }

    /* retrieve the classtype priority */
    ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str);
    if (ret < 0) {
        SCLogInfo("pcre_get_substring() failed");
        goto error;
    }
    if (ct_priority_str == NULL) {
        goto error;
    }

    ct_priority = atoi(ct_priority_str);

    /* Create a new instance of the parsed Classtype string */
    ct_new = SCClassConfAllocClasstype(ct_id, ct_name, ct_desc, ct_priority);
    if (ct_new == NULL)
        goto error;

    /* Check if the Classtype is present in the HashTable.  In case it's present
     * ignore it, as it is a duplicate.  If not present, add it to the table */
    ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0);
    if (ct_lookup == NULL) {
        if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0)
            SCLogDebug("HashTable Add failed");
    } else {
        SCLogDebug("Duplicate classtype found inside classification.config");
        if (ct_new->classtype_desc) SCFree(ct_new->classtype_desc);
        if (ct_new->classtype) SCFree(ct_new->classtype);
        SCFree(ct_new);
    }

    if (ct_name) SCFree((char *)ct_name);
    if (ct_desc) SCFree((char *)ct_desc);
    if (ct_priority_str) SCFree((char *)ct_priority_str);
    return 0;

 error:
    if (ct_name) SCFree((char *)ct_name);
    if (ct_desc) SCFree((char *)ct_desc);
    if (ct_priority_str) SCFree((char *)ct_priority_str);

    return -1;
}
Beispiel #12
0
/*
 * Complements a scaffold; both complementing each contig within it and
 * reversing the order of contigs in the scaffold.
 *
 * Returns 0 on success
 *        -1 on failure
 */
int complement_scaffold(GapIO *io, tg_rec srec) {
    scaffold_t *f;
    int i, j, nc = ArrayMax(io->contig_order);
    scaffold_member_t *contigs;
    tg_rec *crecs;
    HashTable *h;
    reg_order ro;
    reg_buffer_start rs;
    reg_buffer_end re;

    if (!(f = cache_search(io, GT_Scaffold, srec)))
	return -1;
    if (!(f = cache_rw(io, f)))
	return -1;
    cache_incr(io, f);

    /* Complement contigs */
    contigs = ArrayBase(scaffold_member_t, f->contig);
    for (i = 0; i < ArrayMax(f->contig); i++) {
	complement_contig(io, contigs[i].rec);
    }

    /* Reverse the order of the contigs in the scaffold array */
    for (i = 0, j = ArrayMax(f->contig)-1; i < j; i++, j--) {
	scaffold_member_t cr1 = contigs[i];
	contigs[i] = contigs[j];
	contigs[j] = cr1;
    }

    /*
     * Reverse the order of contigs in the contig_order array too.
     * This is the part that really matters. It's also hard as the contigs
     * in the contig order array could be in any order and not adjacent.
     * For our purposes we'll just ensure the contigs in this scaffold in 
     * the contig order array match our freshly complemented scaffold
     * ordering.
     *
     * We initially build a hash table of contigs in this scaffold, and
     * then iterate through contig_order copying out the new contigs whenever
     * one matches.
     */
    h = HashTableCreate(nc, 0);
    for (i = 0; i < ArrayMax(f->contig); i++) {
	HashData hd;
	hd.i = 0;
	HashTableAdd(h, (char *)&contigs[i].rec, sizeof(tg_rec), hd, NULL);
    }

    /* Replace any contig matching the scaffold with the new order */
    crecs = ArrayBase(tg_rec, io->contig_order);
    for (i = j = 0; i < nc; i++) {
	HashItem *hi;
	if (!(hi = HashTableSearch(h, (char *)&crecs[i], sizeof(tg_rec))))
	    continue;

	crecs[i] = contigs[j++].rec;
    }

    /* Send event messages around */
    rs.job = REG_BUFFER_START;
    for (i = 0; i < nc; i++) {
	HashItem *hi;
	if (!(hi = HashTableSearch(h, (char *)&crecs[i], sizeof(tg_rec))))
	    continue;

	contig_notify(io, crecs[i], (reg_data *)&rs);
    }

    ro.job = REG_ORDER;
    for (i = 0; i < nc; i++) {
	HashItem *hi;
	if (!(hi = HashTableSearch(h, (char *)&crecs[i], sizeof(tg_rec))))
	    continue;

	ro.pos = i+1;
	contig_notify(io, crecs[i], (reg_data *)&ro);
    }

    /* Notify the end of our updates */
    re.job = REG_BUFFER_END;
    for (i = 0; i < nc; i++) {
	HashItem *hi;
	if (!(hi = HashTableSearch(h, (char *)&crecs[i], sizeof(tg_rec))))
	    continue;

	contig_notify(io, crecs[i], (reg_data *)&re);
    }

    HashTableDestroy(h, 0);
    cache_decr(io, f);

    return 0;
}
Beispiel #13
0
/*
 * Parse the REGN chunk, add to regn HASH
 *
 * Returns corresponding HashItem * from regn Hash
 */
HashItem *parse_regn(ztr_t *z, ztr_chunk_t *chunk, HashTable *regn_hash) {
    char key[1024];
    char *name;
    HashItem *hi;
    regn_t *regn;
    size_t l;
    
    uncompress_chunk(z, chunk);

    /* the hash key is a combination of the region names and boundaries */
    name = ztr_lookup_mdata_value(z, chunk, "NAME");
    l = snprintf(key, sizeof(key), "names=%s", name);
    if( chunk->dlength ){
        int nbndy = (chunk->dlength-1)/4;
        uint4 *bndy = (uint4 *)(chunk->data+1);
        int ibndy;
	for (ibndy=0; ibndy<nbndy; ibndy++) {
            if( ibndy )
                l += snprintf(key + l, sizeof(key) - l,
			      ";%d", be_int4(bndy[ibndy]));
            else
                l += snprintf(key + l, sizeof(key) - l,
			      " boundaries=%d", be_int4(bndy[ibndy]));
        }
    }

    if (NULL == (hi = (HashTableSearch(regn_hash, key, strlen(key))))) {
        int iregion, nregions = 0;
        char *coord;
	char *cp1;
        uint4 bndy[MAX_REGIONS];
        int ibndy, nbndy = 0;
        HashData hd;

        if( NULL == (regn = (regn_t *)malloc(sizeof(regn_t)))) {
	    return NULL;
	}

	coord = ztr_lookup_mdata_value(z, chunk, "COORD");
	regn->coord = (NULL == coord ? 'B' : *coord );

	regn->region_names = strdup(name);

        cp1 = strtok (regn->region_names,";");
        while(cp1) {
            char *cp2;
            if(NULL == (cp2 = strchr(cp1,':'))) {
                fprintf(stderr, "Invalid region name/code pair %s\n", cp1);
                return NULL;
            }
            *cp2++ = '\0';
            regn->name[nregions] = cp1;
            regn->code[nregions] = *cp2;
            nregions++;
            cp1 = strtok (NULL, ";");
        }

        regn->nregions = nregions;

	if( chunk->dlength ) {
            nbndy = (chunk->dlength-1)/4;
            memcpy(bndy, chunk->data+1, chunk->dlength-1);
	}

        for( iregion=0, ibndy=0; iregion<nregions; iregion++) {
            /* start = (start + length of previous region) or 0 if no previous region */
            /* length = (next boundary - start of region) or -1 if no next boundary */
            if( regn->code[iregion] == 'E' ){
                /* no sequence, length = 0 */
                regn->start[iregion] = (iregion ? (regn->start[iregion-1] + regn->length[iregion-1]) : 0);
                regn->length[iregion] = 0;
            }else{
                if( ibndy > nbndy ){
                    fprintf(stderr, "More name/code pairs than boundaries\n");
                    return NULL;
                }
                regn->start[iregion] = (iregion ? (regn->start[iregion-1] + regn->length[iregion-1]) : 0);
                regn->length[iregion] = (ibndy == nbndy ? -1 : (be_int4(bndy[ibndy])-regn->start[iregion]));
                ibndy++;
            }
        }

        regn->count = 1;
            
	hd.p = regn;
	if (NULL == (hi = HashTableAdd(regn_hash, key, strlen(key), hd, NULL))) {
	    free(regn->region_names);
	    free(regn);
	    return NULL;
	}
    } else {
	regn = (regn_t *)(hi->data.p);
	regn->count++;
    }

    return hi;
}
Beispiel #14
0
int main(int argc, char **argv) {
    HashFile *hf;
    sff_common_header *ch;
    sff_read_header *rh;
    int i, dot, arg;
    char *sff;
    char hdr[31];
    uint64_t index_offset = 0;
    uint32_t index_size, index_skipped;
    FILE *fp, *fpout = NULL;
    int copy_archive = 1;
    

    /* process command line arguments of the form -arg */
    for (argc--, argv++; argc > 0; argc--, argv++) {
	if (**argv != '-' || strcmp(*argv, "--") == 0)
	    break;

	if (strcmp(*argv, "-o") == 0 && argc > 1) {
	    if (NULL == (fpout = fopen(argv[1], "wb+"))) {
		perror(argv[1]);
		return 1;
	    }
	    argv++;
	    argc--;

	} else if (strcmp(*argv, "-t") == 0) {
	    copy_archive = 0;

	} else if (**argv == '-') {
	    usage();
	}

    }

    if (argc < 1)
	usage();

    if (copy_archive == 0 && argc != 1) {
	fprintf(stderr, "-t option only supported with a single sff argument\n");
	return 1;
    }

    /* Create the hash table */
    hf = HashFileCreate(0, HASH_DYNAMIC_SIZE);
    hf->nheaders = 0;
    hf->headers = NULL;

    for (arg = 0; arg < argc; arg++) {
	/* open (and read) the entire sff file */
	sff = argv[arg];

	printf("Indexing %s:\n", sff);
	if (fpout) {
	    if (NULL == (fp = fopen(sff, "rb"))) {
		perror(sff);
		return 1;
	    }
	} else { 
	    if (NULL == (fp = fopen(sff, "rb+"))) {
		perror(sff);
		return 1;
	    }
	}

	/* Read the common header */
	ch = fread_sff_common_header(fp);

	if (ch->index_len && !fpout) {
	    fprintf(stderr, "Archive already contains index.\nReplacing the"
		    " index requires the \"-o outfile\" option.\n");
	    return 1;
	}

	/* Add the SFF common header as a hash file-header */
	hf->nheaders++;
	hf->headers = (HashFileSection *)realloc(hf->headers, hf->nheaders *
						 sizeof(*hf->headers));
	hf->headers[hf->nheaders-1].pos = 0;
	hf->headers[hf->nheaders-1].size = ch->header_len;
	hf->headers[hf->nheaders-1].cached_data = NULL;

	/* Read the index items, adding to the hash */
	index_skipped = 0;
	dot = 0;
	printf("                                                                       |\r|");
	for (i = 0; i < ch->nreads; i++) {
	    int dlen;
	    uint32_t offset;
	    HashData hd;
	    HashFileItem *hfi;
	    
	    if (i >= dot * (ch->nreads/69)) {
		putchar('.');
		fflush(stdout);
		dot++;
	    }

	    /* Skip old index if present */
	    offset = ftell(fp);
	    if (offset == ch->index_offset) {
		fseek(fp, ch->index_len, SEEK_CUR);
		index_skipped = ch->index_len;
		continue;
	    }

	    hfi = (HashFileItem *)calloc(1, sizeof(*hfi));
	    rh = fread_sff_read_header(fp);
	    dlen = (2*ch->flow_len + 3*rh->nbases + 7) & ~7;
	    fseek(fp, dlen, SEEK_CUR);
	
	    hfi->header = hf->nheaders;
	    hfi->footer = 0;
	    hfi->pos = offset - index_skipped;
	    hfi->size = (ftell(fp) - index_skipped) - hfi->pos;
	    hd.p = hfi;

	    HashTableAdd(hf->h, rh->name, rh->name_len, hd, NULL);
	}
	printf("\n");
	HashTableStats(hf->h, stdout);

	index_offset = ftell(fp) - index_skipped;

	/* Copy the archive if needed, minus the old index */
	if (fpout && copy_archive) {
	    char block[8192];
	    size_t len;
	    uint64_t pos = 0;

	    printf("\nCopying archive\n");

	    fseek(fp, 0, SEEK_SET);
	    while (len = fread(block, 1, 8192, fp)) {
		/* Skip previous index */
		if (pos < ch->index_offset && pos+len > ch->index_offset) {
		    len = ch->index_offset - pos;
		    fseek(fp, ch->index_offset + ch->index_len, SEEK_SET);
		}
		if (len && len != fwrite(block, 1, len, fpout)) {
		    fprintf(stderr, "Failed to output new archive\n");
		    return 1;
		}
		pos += len;
	    }
	}
	
	if (!fpout) {
	    /* Save the hash */
	    printf("Saving index\n");
	    fseek(fp, 0, SEEK_END);
	    index_size = HashFileSave(hf, fp, 0);
	    HashFileDestroy(hf);

	    /* Update the common header */
	    fseek(fp, 0, SEEK_SET);
	    fread(hdr, 1, 31, fp);
	    *(uint64_t *)(hdr+8)  = be_int8(index_offset);
	    *(uint32_t *)(hdr+16) = be_int4(index_size);
	    fseek(fp, 0, SEEK_SET);
	    fwrite(hdr, 1, 31, fp);
	}

	fclose(fp);
    }

    if (fpout) {
	/* Save the hash */
	printf("Saving index\n");

	if (!copy_archive) {
	    hf->archive = strdup(argv[0]);
	    index_offset = 0;
	}

	fseek(fpout, 0, SEEK_END);
	index_size = HashFileSave(hf, fpout, 0);
	HashFileDestroy(hf);

	/* Update the common header to indicate index location */
	if (copy_archive) {
	    fseek(fpout, 0, SEEK_SET);
	    fread(hdr, 1, 31, fpout);
	    *(uint64_t *)(hdr+8)  = be_int8(index_offset);
	    *(uint32_t *)(hdr+16) = be_int4(index_size);
	    fseek(fpout, 0, SEEK_SET);
	    fwrite(hdr, 1, 31, fpout);
	}
	fclose(fpout);
    }
    
    return 0;
}