Exemplo n.º 1
0
void test_bsp__tree_can_produce_triangles_from_quads(void) {
	klist_t(poly) *quad = kl_init(poly);
	// I'll make a quad by making a triangle with a missing
	// vertex, then pushing the extra vertex after and recomputing
	float3 quad_verts[] = {{-1.0, 1.0, 0.0},
						  {-1.0, -1.0, 0.0},
						  {1.0, -1.0, 0.0},
						  {1.0, 1.0, 0.0}};
	poly_t *poly = poly_make_triangle(quad_verts[0], quad_verts[1], quad_verts[2]);
	cl_assert_(poly != NULL, "Can't make triangle for test");

	poly_push_vertex(poly, quad_verts[3]);

	cl_assert_(poly_vertex_count(poly) == 4, "Failed to add vertex into quad");
	poly_update(poly);

	// Build a tree of the quad
	klist_t(poly) *lpoly = kl_init(poly);
	*kl_pushp(poly, lpoly) = poly;
	bsp_node_t *quad_bsp = bsp_build(NULL, lpoly, 1);
	cl_assert(quad_bsp);

	klist_t(poly) *tris = bsp_to_polygons(quad_bsp, 1, NULL);
	cl_assert_equal_i(tris->size, 2);

	kl_destroy(poly, quad);
	kl_destroy(poly, lpoly);
	if(tris) kl_destroy(poly, tris);
}
Exemplo n.º 2
0
void test_bsp__initialize(void) {
	bsp = alloc_bsp_node();
	poly_t *poly = NULL;
	polygons = kl_init(poly);

	float3 fs[] = {{-0.5, 0.0, 0.0},
				   {0.5, 0.0, 0.0},
				   {0.0, 0.5, 0.0}};
	poly = poly_make_triangle(fs[0], fs[1], fs[2]);
	cl_assert_(poly != NULL, "Out of memory");
	*kl_pushp(poly, polygons) = poly;

	float3 fs2[] = {{-0.5, 0.0, -0.5},
				   {0.5, 0.0, -0.5},
				   {0.0, 0.5, -0.5}};
	poly = poly_make_triangle(fs2[0], fs2[1], fs2[2]);
	cl_assert_(poly != NULL, "Out of memory");
	*kl_pushp(poly, polygons) = poly;

	float3 fs3[] = {{-0.5, 0.0, 0.5},
				   {0.5, 0.0, 0.5},
				   {0.0, 0.5, 0.5}};
	poly = poly_make_triangle(fs3[0], fs3[1], fs3[2]);
	cl_assert_(poly != NULL, "Out of memory");
	*kl_pushp(poly, polygons) = poly;

 	float3 fs4[] = {{0.0, 0.0, -1.0},
					{0.0, 0.0, 1.0},
					{0.0, 1.0, 0.0}};
	poly = poly_make_triangle(fs4[0], fs4[1], fs4[2]);
	cl_assert_(poly != NULL, "Out of memory");
	*kl_pushp(poly, polygons) = poly;

	cl_assert_(bsp != NULL, "Out of memory");
	cl_assert_(bsp_build(bsp, polygons, 1) != NULL, "Failed to build bsp tree");

	stl_object *stl_cube = stl_read_file(cube_stl_file, 1);
	cl_assert(stl_cube != NULL);
	klist_t(poly) *cube_polys = kl_init(poly);
	for(int i = 0; i < stl_cube->facet_count; i++) {
		poly_t *p = poly_make_triangle(stl_cube->facets[i].vertices[0],
									   stl_cube->facets[i].vertices[1],
									   stl_cube->facets[i].vertices[2]);
		cl_assert(p != NULL);
		*kl_pushp(poly, cube_polys) = p;
	}
	cube_bsp = bsp_build(NULL, cube_polys, 1);
	kl_destroy(poly, cube_polys);
	cl_assert(cube_bsp != NULL);
}
Exemplo n.º 3
0
void test_bsp__cube_bsp_can_return_poly_list_of_equal_length(void) {
	// We test that when we get a list of polygons from a BSP tree of a cube
	// and assert that we have the same number of polygons as when we started.
	//
	// A cube is nice here because no faces need to be split, so polygon
	// counts before and after remain the same.
	char cube_path[] = CLAR_FIXTURE_PATH "cube.stl";
	stl_object *stl_cube = stl_read_file(cube_path, 0);
	klist_t(poly) *cube_polys = kl_init(poly);
	cl_assert(stl_cube != NULL);
	cl_assert(stl_cube->facet_count > 0);

	for(int i = 0; i < stl_cube->facet_count; i++) {
		stl_facet *face = &stl_cube->facets[i];
		poly_t *poly = poly_make_triangle(face->vertices[0], face->vertices[1], face->vertices[2]);
		*kl_pushp(poly, cube_polys) = poly;
		cl_assert(poly);
	}

	bsp_node_t *cube_bsp = alloc_bsp_node();
	cl_assert(cube_bsp != NULL);
	cl_assert(bsp_build(cube_bsp, cube_polys, 1) == cube_bsp);
	klist_t(poly) *results = bsp_to_polygons(cube_bsp, 0, NULL);

	cl_assert_equal_i(results->size, stl_cube->facet_count);

	if(stl_cube) stl_free(stl_cube);
	if(results) kl_destroy(poly, results);
	kl_destroy(poly, cube_polys);
}
Exemplo n.º 4
0
void test_bsp__tree_can_clip_tree(void) {
	klist_t(poly) *polys = kl_init(poly);
	float3 tr1[] = {{-0.2, 0.0, 0.0},
					{0.2, 0.0, 0.0},
					{0.0, 0.2, 0.0}};
	float3 tr2[] = {{-0.2, 0.0, 100.0},
					{0.2, 0.0, 100.0},
					{0.0, 0.2, 1000.0}};

	*kl_pushp(poly, polys) = poly_make_triangle(tr1[0], tr1[1], tr1[2]);
	*kl_pushp(poly, polys) = poly_make_triangle(tr2[0], tr2[1], tr2[2]);
	cl_assert_equal_i(polys->size, 2);

	bsp_node_t *tr_bsp = bsp_build(NULL, polys, 1);
	cl_assert(tr_bsp != NULL);

	cl_assert(bsp_clip(tr_bsp, cube_bsp) != NULL);

	klist_t(poly) *clipped = bsp_to_polygons(tr_bsp, 0, NULL);

	cl_assert_equal_i(clipped->size, 1);

	// Make sure we clipped the poly inside the cube, and kept
	// the poly outside
	float3 *v = &kl_val(kl_begin(clipped))->vertices[0];
	cl_assert_((*v)[2] >= 99.0, "Should have kept the vertex outside the cube, not inside.");

	kl_destroy(poly, polys);
}
Exemplo n.º 5
0
bsp_node_t *alloc_bsp_node(void) {
	bsp_node_t *node = NULL;
	check_mem(node = calloc(1, sizeof(bsp_node_t)));
	node->polygons = kl_init(poly);
	return node;
error:
	return NULL;
}
Exemplo n.º 6
0
void event_init()
{
  // Initialize the event queues
  deferred_events = kl_init(Event);
  immediate_events = kl_init(Event);
  // Initialize input events
  input_init();
  // Timer to wake the event loop if a timeout argument is passed to
  // `event_poll`
  // Signals
  signal_init();
  // Jobs
  job_init();
  // Channels
  channel_init();
  // Servers
  server_init();
}
Exemplo n.º 7
0
void event_init(void)
{
  // Initialize the event queues
  deferred_events = kl_init(Event);
  immediate_events = kl_init(Event);
  // early msgpack-rpc initialization
  msgpack_rpc_init_method_table();
  msgpack_rpc_helpers_init();
  // Initialize input events
  input_init();
  // Timer to wake the event loop if a timeout argument is passed to
  // `event_poll`
  // Signals
  signal_init();
  // Jobs
  job_init();
  // finish mspgack-rpc initialization
  channel_init();
  server_init();
  terminal_init();
}
Exemplo n.º 8
0
void loop_init(Loop *loop, void *data)
{
  uv_loop_init(&loop->uv);
  loop->recursive = 0;
  loop->uv.data = loop;
  loop->children = kl_init(WatcherPtr);
  loop->children_stop_requests = 0;
  loop->events = multiqueue_new_parent(loop_on_put, loop);
  loop->fast_events = multiqueue_new_child(loop->events);
  loop->thread_events = multiqueue_new_parent(NULL, NULL);
  uv_mutex_init(&loop->mutex);
  uv_async_init(&loop->uv, &loop->async, async_cb);
  uv_signal_init(&loop->uv, &loop->children_watcher);
  uv_timer_init(&loop->uv, &loop->children_kill_timer);
  uv_timer_init(&loop->uv, &loop->poll_timer);
}
Exemplo n.º 9
0
void event_init()
{
  // Initialize the event queue
  event_queue = kl_init(Event);
  // Initialize input events
  input_init();
  // Timer to wake the event loop if a timeout argument is passed to
  // `event_poll`
  // Signals
  signal_init();
  // Jobs
  job_init();
  uv_timer_init(uv_default_loop(), &timer);
  // This prepare handle that actually starts the timer
  uv_prepare_init(uv_default_loop(), &timer_prepare);
}
Exemplo n.º 10
0
// Called when the manager sends a complete message
void messageArrivedFromManager() {
	printf ("Message arrived: >%s< for >%s<\r\n", commandMessage, commandClientId);

	// See if the client is connected, if so immediately forward
	khiter_t k = kh_get(clientStatuses, clientStatuses, (char*)commandClientId); // Find it in the hash
	if (k != kh_end(clientStatuses)) { // Was it in the hash?
		clientStatus* status = kh_value(clientStatuses, k); // Grab the clientStatus from the hash
		snprintf(httpResponse, HTTP_RESPONSE_SIZE, HTTP_TEMPLATE, commandMessageLen, commandMessage); // Compose the response message
		write(status->io.fd, httpResponse, strlen(httpResponse)); // Send it
		closeConnection((ev_io*)status); // Close the conn
		return;
	}

	// If not, add to a queue
	khiter_t q = kh_get(queue, queue, (char*)commandClientId); // See if this client is already in the queue
	if (q == kh_end(queue)) {
		printf("Creating queue for %s\r\n", commandClientId);
		// This client needs to be added to the queue
		// First make a new list
		klist_t(messages) *newMessageList = kl_init(messages);
		*kl_pushp(messages, newMessageList) = strdup((char*)commandMessage); // Add the message to the list
		// Now make a new hash entry pointing to this new list
		int ret;
		q = kh_put(queue, queue, strdup((char*)commandClientId), &ret);
		kh_value(queue, q) = newMessageList;
	} else {
		printf("Adding to the queue for %s\r\n", commandClientId);
		// This client is in the queue already eg it has a hash entry
		// Pushp puts this message at the end of the queue, so that shift will grab the oldest first (like a FIFO)
		*kl_pushp(messages, kh_value(queue, q)) = strdup((char*)commandMessage);
	}

	// Now do a printout of the hash list
	for (khiter_t qi = kh_begin(queue); qi < kh_end(queue); qi++) {
		if (kh_exist(queue, qi)) {
			printf("Queue for %s\n", kh_key(queue,qi));
			klist_t(messages) *list = kh_value(queue, qi);
			kliter_t(messages) *li;
			for (li = kl_begin(list); li != kl_end(list); li = kl_next(li))
				printf("%s\n", kl_val(li));
			printf("----\n");
		}
	}
}
Exemplo n.º 11
0
 *                     Ján Mochňak,    <*****@*****.**>
 *                     Tibor Dudlák,   <*****@*****.**>
 *                     Dávid Prexta,   <*****@*****.**>
 *                     Martin Krajňák, <*****@*****.**>
 *                     Patrik Segedy,  <*****@*****.**>
 * All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * license.txt file in the root directory of this source tree.
 */

#include "instruction.h"

result_t append_instr_from_expr(klist_t(instruction_list) *dest, klist_t(expr_stack) *expr) {
    result_t ret;
    klist_t(expr_stack) *buff = kl_init(expr_stack);
    int offset = 0;

    for (kliter_t(expr_stack) *it = kl_begin(expr); it != kl_end(expr); it = kl_next(it)) {
        expr_t *curr = &kl_val(it);

        if (EXPR_IS_INT(curr) || EXPR_IS_DOUBLE(curr) || EXPR_IS_STRING(curr) || EXPR_IS_OFFSET(curr)) {
            expr_t copy;
            expr_init(&copy);
            if ((ret = expr_copy(&copy, curr)) != EOK) {
                debug_print("%s\n", "<");
                return ret;
            }
            *kl_push(expr_stack, buff) = copy;
            offset++;
        } else if (EXPR_IS_OPERAND(curr)) {
Exemplo n.º 12
0
void test_polygon__initialize(void) {
	faces = kl_init(poly);

	// Set up three triangles, one on top of each other
	// stored in list `faces` for easy cleanup
	// and refferenced in `top` and `bottom`, and `square`
	// used for inversion testing and area checking.
	// And a square for non-triangular area tests and
	float3 square_faces[] = {{0.0, 0.0, 0.0},
							 {1.0, 0.0, 0.0},
							 {1.0, 1.0, 0.0},
							 {0.0, 1.0, 0.0}};
	square = alloc_poly();
	cl_assert(square != NULL);

	for(int i = 0; i < 3; i++) {
		cl_assert_(poly_push_vertex(square, square_faces[i]),
				   "Failed to add square vertex");
	}
	cl_assert_equal_i(poly_vertex_count(square), 3);
	*kl_pushp(poly, faces) = square;

	// Set up a quad
	quad = alloc_poly();
	cl_assert(quad != NULL);

	for(int i = 0; i < 4; i++) {
		cl_assert_(poly_push_vertex(quad, square_faces[i]),
				   "Failed to add quad vertex.");
	}
	cl_assert_equal_i(poly_vertex_count(quad), 4);
	*kl_pushp(poly, faces) = quad;

	// Set up an invalid polygon which is just a line
	line = alloc_poly();
	cl_assert(line != NULL);

	cl_assert(poly_push_vertex(line, square_faces[0]));
	cl_assert(poly_push_vertex(line, square_faces[1]));
	cl_assert(poly_push_vertex(line, square_faces[2]));

	// Force the last vertex to be square_faces[0], then force a recompute
	line->vertices[2][0] = line->vertices[0][0];
	line->vertices[2][1] = line->vertices[0][1];
	line->vertices[2][2] = line->vertices[0][2];
	cl_assert(poly_update(line) == 0);

	*kl_pushp(poly, faces) = line;

	// Set up two triangles, one on top of each other
	float3 fs[] = {{-0.5, 0.0, 0.0},
				   {0.5, 0.0, 0.0},
				   {0.0, 0.5, 0.0}};
	bottom = poly_make_triangle(fs[0], fs[1], fs[2]);
	cl_assert_(bottom != NULL, "Out of memory");
	*kl_pushp(poly, faces) = bottom;

	for(int i = 0; i < 3; i++) {
		fs[i][2] += 1.0;
	}
	top = poly_make_triangle(fs[0], fs[1], fs[2]);
	cl_assert_(top != NULL, "Out of memory");
	*kl_pushp(poly, faces) = top;

	cl_assert_equal_i(poly_classify_poly(top, bottom), BACK);
	cl_assert_equal_i(poly_classify_poly(bottom, top), FRONT);
}
Exemplo n.º 13
0
static void trans_tbl_init(bam_hdr_t* out, bam_hdr_t* translate, trans_tbl_t* tbl, bool merge_rg, bool merge_pg)
{
    tbl->n_targets = translate->n_targets;
    tbl->tid_trans = (int*)calloc(translate->n_targets, sizeof(int));
    tbl->rg_trans = kh_init(c2c);
    tbl->pg_trans = kh_init(c2c);
    if (!tbl->tid_trans || !tbl->rg_trans || !tbl->pg_trans) { perror("out of memory"); exit(-1); }

    int32_t out_len = out->l_text;
    while (out_len > 0 && out->text[out_len-1] == '\n') {--out_len; } // strip trailing \n's
    kstring_t out_text = { 0, 0, NULL };
    kputsn(out->text, out_len, &out_text);

    int i, min_tid = -1;
    tbl->lost_coord_sort = false;

    khash_t(c2i) *out_tid = kh_init(c2i);
    for (i = 0; i < out->n_targets; ++i) {
        int ret;
        khiter_t iter = kh_put(c2i, out_tid, out->target_name[i], &ret);
        if (ret <= 0) abort();
        kh_value(out_tid, iter) = i;
    }

    for (i = 0; i < translate->n_targets; ++i) {
        khiter_t iter = kh_get(c2i, out_tid, translate->target_name[i]);

        if (iter == kh_end(out_tid)) { // Append missing entries to out
            tbl->tid_trans[i] = out->n_targets++;
            out->target_name = (char**)realloc(out->target_name, sizeof(char*)*out->n_targets);
            out->target_name[out->n_targets-1] = strdup(translate->target_name[i]);
            out->target_len = (uint32_t*)realloc(out->target_len, sizeof(uint32_t)*out->n_targets);
            out->target_len[out->n_targets-1] = translate->target_len[i];
            // grep line with regex '^@SQ.*\tSN:%s(\t.*$|$)', translate->target_name[i]
            // from translate->text
            regex_t sq_id;
            regmatch_t* matches = (regmatch_t*)calloc(2, sizeof(regmatch_t));
            if (matches == NULL) { perror("out of memory"); exit(-1); }
            kstring_t seq_regex = { 0, 0, NULL };
            ksprintf(&seq_regex, "^@SQ.*\tSN:%s(\t.*$|$)", translate->target_name[i]);
            regcomp(&sq_id, seq_regex.s, REG_EXTENDED|REG_NEWLINE);
            free(seq_regex.s);
            if (regexec(&sq_id, translate->text, 1, matches, 0) != 0)
            {
                fprintf(pysamerr, "[trans_tbl_init] @SQ SN (%s) found in binary header but not text header.\n",translate->target_name[i]);
                exit(1);
            }
            regfree(&sq_id);

            // Produce our output line and append it to out_text
            kputc('\n', &out_text);
            kputsn(translate->text+matches[0].rm_so, matches[0].rm_eo-matches[0].rm_so, &out_text);

            free(matches);
        } else {
            tbl->tid_trans[i] = kh_value(out_tid, iter);
        }
        if (tbl->tid_trans[i] > min_tid) {
            min_tid = tbl->tid_trans[i];
        } else {
            tbl->lost_coord_sort = true;
        }
    }
    kh_destroy(c2i, out_tid);

    // grep @RG id's
    regex_t rg_id;
    regmatch_t* matches = (regmatch_t*)calloc(2, sizeof(regmatch_t));
    if (matches == NULL) { perror("out of memory"); exit(-1); }
    regcomp(&rg_id, "^@RG.*\tID:([!-)+-<>-~][ !-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE);
    char* text = translate->text;
    klist_t(hdrln) *rg_list = kl_init(hdrln);
    while(1) { //   foreach rg id in translate's header
        if (regexec(&rg_id, text, 2, matches, 0) != 0) break;
        // matches[0] is the whole @RG line; matches[1] is the ID field value
        kstring_t match_id = { 0, 0, NULL };
        kputsn(text+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &match_id);

        // is our matched ID in our output list already
        regex_t rg_id_search;
        kstring_t rg_regex = { 0, 0, NULL };
        ksprintf(&rg_regex, "^@RG.*\tID:%s(\t.*$|$)", match_id.s);
        regcomp(&rg_id_search, rg_regex.s, REG_EXTENDED|REG_NEWLINE|REG_NOSUB);
        free(rg_regex.s);
        kstring_t transformed_id = { 0, 0, NULL };
        bool transformed_equals_match;
        if (regexec(&rg_id_search, out->text, 0, NULL, 0) != 0  || merge_rg) {
            // Not in there so can add it as 1-1 mapping
            kputs(match_id.s, &transformed_id);
            transformed_equals_match = true;
        } else {
            // It's in there so we need to transform it by appending random number to id
            ksprintf(&transformed_id, "%s-%0lX", match_id.s, lrand48());
            transformed_equals_match = false;
        }
        regfree(&rg_id_search);

        // Insert it into our translation map
        int in_there = 0;
        khiter_t iter = kh_put(c2c, tbl->rg_trans, ks_release(&match_id), &in_there);
        char *transformed_id_s = ks_release(&transformed_id);
        kh_value(tbl->rg_trans,iter) = transformed_id_s;
        // take matched line and replace ID with transformed_id
        kstring_t transformed_line = { 0, 0, NULL };
        if (transformed_equals_match) {
            kputsn(text+matches[0].rm_so, matches[0].rm_eo-matches[0].rm_so, &transformed_line);
        } else {
            kputsn(text+matches[0].rm_so, matches[1].rm_so-matches[0].rm_so, &transformed_line);
            kputs(transformed_id_s, &transformed_line);
            kputsn(text+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line);
        }

        if (!(transformed_equals_match && merge_rg)) {
            // append line to linked list for PG processing
            char** ln = kl_pushp(hdrln, rg_list);
            *ln = ks_release(&transformed_line);  // Give away to linked list
        }
        else free(transformed_line.s);

        text += matches[0].rm_eo; // next!
    }
    regfree(&rg_id);

    // Do same for PG id's
    regex_t pg_id;
    regcomp(&pg_id, "^@PG.*\tID:([!-)+-<>-~][ !-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE);
    text = translate->text;
    klist_t(hdrln) *pg_list = kl_init(hdrln);
    while(1) { //   foreach pg id in translate's header
        if (regexec(&pg_id, text, 2, matches, 0) != 0) break;
        kstring_t match_id = { 0, 0, NULL };
        kputsn(text+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &match_id);

        // is our matched ID in our output list already
        regex_t pg_id_search;
        kstring_t pg_regex = { 0, 0, NULL };
        ksprintf(&pg_regex, "^@PG.*\tID:%s(\t.*$|$)", match_id.s);
        regcomp(&pg_id_search, pg_regex.s, REG_EXTENDED|REG_NEWLINE|REG_NOSUB);
        free(pg_regex.s);
        kstring_t transformed_id = { 0, 0, NULL };
        bool transformed_equals_match;
        if (regexec(&pg_id_search, out->text, 0, NULL, 0) != 0 || merge_pg) {
            // Not in there so can add it as 1-1 mapping
            kputs(match_id.s, &transformed_id);
            transformed_equals_match = true;
        } else {
            // It's in there so we need to transform it by appending random number to id
            ksprintf(&transformed_id, "%s-%0lX", match_id.s, lrand48());
            transformed_equals_match = false;
        }
        regfree(&pg_id_search);

        // Insert it into our translation map
        int in_there = 0;
        khiter_t iter = kh_put(c2c, tbl->pg_trans, ks_release(&match_id), &in_there);
        char *transformed_id_s = ks_release(&transformed_id);
        kh_value(tbl->pg_trans,iter) = transformed_id_s;
        // take matched line and replace ID with transformed_id
        kstring_t transformed_line = { 0, 0, NULL };
        if (transformed_equals_match) {
            kputsn(text+matches[0].rm_so, matches[0].rm_eo-matches[0].rm_so, &transformed_line);
        } else {
            kputsn(text+matches[0].rm_so, matches[1].rm_so-matches[0].rm_so, &transformed_line);
            kputs(transformed_id_s, &transformed_line);
            kputsn(text+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line);
        }

        if (!(transformed_equals_match && merge_pg)) {
            // append line to linked list for PP processing
            char** ln = kl_pushp(hdrln, pg_list);
            *ln = ks_release(&transformed_line);  // Give away to linked list
        }
        else free(transformed_line.s);
        text += matches[0].rm_eo; // next!
    }
    regfree(&pg_id);
    // need to translate PP's on the fly in second pass because they may not be in correct order and need complete tbl->pg_trans to do this
    // for each line {
    // with ID replaced with tranformed_id and PP's transformed using the translation table
    // }
    regex_t pg_pp;
    regcomp(&pg_pp, "^@PG.*\tPP:([!-)+-<>-~][!-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE);
    kliter_t(hdrln) *iter = kl_begin(pg_list);
    while (iter != kl_end(pg_list)) {
        char* data = kl_val(iter);

        kstring_t transformed_line = { 0, 0, NULL };
        // Find PP tag
        if (regexec(&pg_pp, data, 2, matches, 0) == 0) {
            // Lookup in hash table
            kstring_t pp_id = { 0, 0, NULL };
            kputsn(data+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &pp_id);

            khiter_t k = kh_get(c2c, tbl->pg_trans, pp_id.s);
            free(pp_id.s);
            char* transformed_id = kh_value(tbl->pg_trans,k);
            // Replace
            kputsn(data, matches[1].rm_so-matches[0].rm_so, &transformed_line);
            kputs(transformed_id, &transformed_line);
            kputsn(data+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line);
        } else { kputs(data, &transformed_line); }
        // Produce our output line and append it to out_text
        kputc('\n', &out_text);
        kputsn(transformed_line.s, transformed_line.l, &out_text);

        free(transformed_line.s);
        free(data);
        iter = kl_next(iter);
    }
    regfree(&pg_pp);

    // Need to also translate @RG PG's on the fly too
    regex_t rg_pg;
    regcomp(&rg_pg, "^@RG.*\tPG:([!-)+-<>-~][!-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE);
    kliter_t(hdrln) *rg_iter = kl_begin(rg_list);
    while (rg_iter != kl_end(rg_list)) {
        char* data = kl_val(rg_iter);

        kstring_t transformed_line = { 0, 0, NULL };
        // Find PG tag
        if (regexec(&rg_pg, data, 2, matches, 0) == 0) {
            // Lookup in hash table
            kstring_t pg_id = { 0, 0, NULL };
            kputsn(data+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &pg_id);

            khiter_t k = kh_get(c2c, tbl->pg_trans, pg_id.s);
            free(pg_id.s);
            char* transformed_id = kh_value(tbl->pg_trans,k);
            // Replace
            kputsn(data, matches[1].rm_so-matches[0].rm_so, &transformed_line);
            kputs(transformed_id, &transformed_line);
            kputsn(data+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line);
        } else { kputs(data, &transformed_line); }
        // Produce our output line and append it to out_text
        kputc('\n', &out_text);
        kputsn(transformed_line.s, transformed_line.l, &out_text);

        free(transformed_line.s);
        free(data);
        rg_iter = kl_next(rg_iter);
    }

    regfree(&rg_pg);
    kl_destroy(hdrln,pg_list);
    kl_destroy(hdrln,rg_list);
    free(matches);

    // Add trailing \n and write back to header
    free(out->text);
    kputc('\n', &out_text);
    out->l_text = out_text.l;
    out->text = ks_release(&out_text);
}