/* json_append_array args: * - lua_State * - JSON strbuf * - Size of passwd Lua array (top of stack) */ static void json_append_array(lua_State *l, json_config_t *cfg, strbuf_t *json, int array_length) { int comma, i; json_encode_descend(l, cfg); strbuf_append_char(json, '['); comma = 0; for (i = 1; i <= array_length; i++) { if (comma) strbuf_append_char(json, ','); else comma = 1; lua_rawgeti(l, -1, i); json_append_data(l, cfg, json); lua_pop(l, 1); } strbuf_append_char(json, ']'); cfg->current_depth--; }
static void fix_string(bool retain_backslashes, int skip_count, char endchar) { StrBuf *out = strbuf_new(); int c; for (c = 1+skip_count; yytext[c] != endchar; c++) { char ch = yytext[c]; if (ch == '\\' && c+1 < yyleng) { ch = yytext[++c]; if (retain_backslashes) { strbuf_append_char(out, '\\'); } else { switch (ch) { case 'a': ch = '\a'; break; case 'b': ch = '\b'; break; case 't': ch = '\t'; break; case 'n': ch = '\n'; break; case 'v': ch = '\v'; break; case 'f': ch = '\f'; break; case 'r': ch = '\r'; break; case 'e': case 'E': ch = 27; break; } } } strbuf_append_char(out, ch); } set_string(strbuf_free_to_string(out)); }
void graph_info_make_intersect(const GraphInfo *ginfo, StrBuf *intersect_name) { if(intersect_name->end > 0) strbuf_append_char(intersect_name, ','); strbuf_append_str(intersect_name, ginfo->sample_name.b); if(ginfo->cleaning.is_graph_intersection) { strbuf_append_char(intersect_name, ','); strbuf_append_str(intersect_name, ginfo->cleaning.intersection_name.b); } }
// Strip indels ('-') from allele and add to string buffer static inline void print_vcf_allele(const char *allele, size_t len, int8_t prev_base, int8_t next_base, StrBuf *sbuf) { size_t i; if(prev_base > 0) strbuf_append_char(sbuf, char_to_vcf_char(prev_base)); strbuf_ensure_capacity(sbuf, sbuf->end+len); for(i = 0; i < len; i++) { if(allele[i] != '-') sbuf->b[sbuf->end++] = char_to_vcf_char(allele[i]); } sbuf->b[sbuf->end] = 0; if(next_base > 0) strbuf_append_char(sbuf, char_to_vcf_char(next_base)); }
// Remember to free the result void futil_get_strbuf_of_dir_path(const char *path, StrBuf *dir) { char *tmp = strdup(path); strbuf_set(dir, dirname(tmp)); strbuf_append_char(dir, '/'); ctx_free(tmp); }
static void curl_thread_done(uv_work_t *w, int _) { luv_curl_t *lc = (luv_curl_t *)w->data; lua_State *L = lc->L; free(w); if (lc->stat == DOWNLOADING) lc->stat = DONE; // 1 if (lc->curl_ret == 0 && lc->retsb) { strbuf_append_char(lc->retsb, 0); lua_pushstring(L, lc->retsb->buf); } else lua_pushnil(L); if (lc->retfp) fclose(lc->retfp); // 2 getinfo(lc); push_curl_stat(lc); lua_do_global_callback(lc->L, "curl_done", lc->c, 2, 1); lua_do_global_callback(lc->L, "curl_cancel", lc->c, 0, 0); curl_easy_cleanup(lc->c); if (lc->retsb) strbuf_free(lc->retsb); if (lc->retfname) free(lc->retfname); }
/** * * @param widget * @param msg */ void cwt_msgbox_set_msg(CWT_WIDGET_PTR widget, const CWT_CHAR* msg) { if( msg ) { CWT_WIDGET_PTR label; const CWT_CHAR *ptr = msg; StringBufferPtr sb; sb = strbuf_new_defaults(); while( *ptr ) { if( *ptr == '\n' ) { label = cwt_new_widget(0, CWT_WT_LABEL, widget); cwt_label_set_text(label, strbuf_cstr(sb)); strbuf_clear(sb); } else { strbuf_append_char(sb, *ptr); } ptr++; } if( strbuf_size(sb) > 0 ) { label = cwt_new_widget(0, CWT_WT_LABEL, widget); cwt_label_set_text(label, strbuf_cstr(sb)); } strbuf_delete(sb); widget->need_layout = TRUE; } }
static void *parse_section(struct parser *parser) { struct lexeme *lexeme; size_t name_len; if (!lexeme_buffer_consume(&parser->buffer, &lexeme)) return NULL; strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len); name_len = lexeme->value.len; strbuf_append_char(&parser->strbuf, '\0'); while (lexeme_buffer_consume(&parser->buffer, &lexeme)) { strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len); if (parser->buffer.population >= 1) strbuf_append_char(&parser->strbuf, ' '); } struct config_line line = { .type = CONFIG_LINE_TYPE_SECTION, .name = strbuf_get_buffer(&parser->strbuf), .param = line.name + name_len + 1 }; if (!config_buffer_emit(&parser->items, &line)) return NULL; return parse_config; } static void *parse_section_shorthand(struct parser *parser) { void *next_state = parse_section(parser); if (next_state) { struct config_line line = { .type = CONFIG_LINE_TYPE_SECTION_END }; if (!config_buffer_emit(&parser->items, &line)) return NULL; return next_state; } return NULL; }
static void json_append_object(lua_State *l, json_config_t *cfg, strbuf_t *json) { int comma, keytype; json_encode_descend(l, cfg); /* Object */ strbuf_append_char(json, '{'); lua_pushnil(l); /* table, startkey */ comma = 0; while (lua_next(l, -2) != 0) { if (comma) strbuf_append_char(json, ','); else comma = 1; /* table, key, value */ keytype = lua_type(l, -2); if (keytype == LUA_TNUMBER) { strbuf_append_char(json, '"'); json_append_number(l, json, -2, cfg); strbuf_append_mem(json, "\":", 2); } else if (keytype == LUA_TSTRING) { json_append_string(l, json, -2); strbuf_append_char(json, ':'); } else { json_encode_exception(l, cfg, -2, "table key must be a number or string"); /* never returns */ } /* table, key, value */ json_append_data(l, cfg, json); lua_pop(l, 1); /* table, key */ } strbuf_append_char(json, '}'); cfg->current_depth--; }
static char *list2lines(GList *list) { struct strbuf *s = strbuf_new(); while (list) { strbuf_append_str(s, (char*)list->data); strbuf_append_char(s, '\n'); free(list->data); list = g_list_delete_link(list, list); } return strbuf_free_nobuf(s); }
void graph_info_append_intersect(ErrorCleaning *cleaning, const char *intersect_name) { if(!cleaning->is_graph_intersection) { strbuf_set(&cleaning->intersection_name, intersect_name); } else { strbuf_append_char(&cleaning->intersection_name, ','); strbuf_append_str(&cleaning->intersection_name, intersect_name); } cleaning->is_graph_intersection = true; }
/* json_append_array args: * - lua_State * - JSON strbuf * - Size of passwd Lua array (top of stack) */ static void json_append_array(lua_State *l, struct luaL_serializer *cfg, int current_depth, strbuf_t *json, int array_length) { int comma, i; strbuf_append_char(json, '['); comma = 0; for (i = 1; i <= array_length; i++) { if (comma) strbuf_append_char(json, ','); else comma = 1; lua_rawgeti(l, -1, i); json_append_data(l, cfg, current_depth, json); lua_pop(l, 1); } strbuf_append_char(json, ']'); }
static char * var_get_display_flags(DCVariable *var) { StrBuf *out; uint32_t c; uint32_t flags; flags = *(uint32_t *) var->value; out = strbuf_new(); for (c = 0; c < display_flag_count; c++) { if (flags & display_flag_details[c].flag) { if (!strbuf_is_empty(out)) strbuf_append_char(out, ' '); strbuf_append(out, display_flag_details[c].name); } } return strbuf_free_to_string(out); }
char seq_read_all_bases_fasta(SeqFile *sf, StrBuf *sbuf) { int c; while((c = seq_getc(sf)) != -1 && c != '>') { if(c != '\r' && c != '\n') { strbuf_append_char(sbuf, (char)c); seq_readline(sbuf, sf); strbuf_chomp(sbuf); } sf->line_number++; } if(c == '>') sf->read_line_start = 1; return 1; }
void vcf_hdrtxt_append_commands(cJSON *command, StrBuf *hdr, const char *path) { bool first; for(; command != NULL; command = command->next) { cJSON *key = json_hdr_get(command, "key", cJSON_String, path); cJSON *cmd = json_hdr_get(command, "cmd", cJSON_Array, path); cJSON *cwd = json_hdr_get(command, "cwd", cJSON_String, path); cJSON *prev = json_hdr_get(command, "prev", cJSON_Array, path); cJSON *ver = json_hdr_try(command, "mccortex",cJSON_String, path); prev = prev->child; // result could be NULL if(prev && prev->type != cJSON_String) die("Invalid 'prev' field"); strbuf_append_str(hdr, "##mccortex_"); strbuf_append_str(hdr, key->valuestring); strbuf_append_str(hdr, "=<prev=\""); strbuf_append_str(hdr, prev ? prev->valuestring : "NULL"); if(prev) { while((prev = prev->next) != NULL) { strbuf_append_str(hdr, ";"); strbuf_append_str(hdr, prev->valuestring); } } strbuf_append_str(hdr, "\",cmd=\""); for(first = true, cmd = cmd->child; cmd; cmd = cmd->next, first = false) { if(!first) strbuf_append_char(hdr, ' '); strbuf_append_str(hdr, cmd->valuestring); } strbuf_append_str(hdr, "\",cwd=\""); strbuf_append_str(hdr, cwd->valuestring); strbuf_append_str(hdr, "\""); if(ver) { strbuf_append_str(hdr, ",version=\""); strbuf_append_str(hdr, ver->valuestring); strbuf_append_str(hdr, "\""); } strbuf_append_str(hdr, ">\n"); } }
/* Note: It is kind of stupid to first call strbuf_free_to_string, * then later free (above this function). But with the current API * of strbuf_free there's no other way! */ char * expand_substitution(const char *repl, MatchState *ms, uint32_t subc, SubmatchSpec *subv) { StrBuf *buf = strbuf_new(); /* XXX: memory management */ bool escaped = false; uint32_t c; for (c = 0; repl[c] != '\0'; c++) { if (!escaped && repl[c] == '$') { uint32_t d; if (repl[c+1] == '{') { for (d = c+2; repl[d] != '}' && repl[d] != '\0'; d++); if (repl[d] != '\0') { if (expand_variable(buf, repl+c+2, d-c-2, ms, subc, subv)) { c = d; continue; } } } else if (isdigit(repl[c+1])) { for (d = c+2; isdigit(repl[d]); d++); if (expand_variable(buf, repl+c+1, d-c-1, ms, subc, subv)) { c = d-1; continue; } } else if (repl[c+1] != '\0' && strchr("`'&", repl[c+1]) != NULL) { expand_variable(buf, repl+c+1, 1, ms, subc, subv); c++; continue; } } escaped = (!escaped && repl[c] == '\\'); if (!escaped) strbuf_append_char(buf, repl[c]); } return strbuf_free_to_string(buf); }
void graph_info_merge(GraphInfo *dst, const GraphInfo *src) { // Update sample name if(strcmp(src->sample_name.b,"undefined") != 0) { if(strcmp(dst->sample_name.b,"undefined") == 0) { strbuf_set_buff(&dst->sample_name, &src->sample_name); } else { strbuf_append_char(&dst->sample_name, ','); strbuf_append_str(&dst->sample_name, src->sample_name.b); } } uint64_t total_sequence = dst->total_sequence + src->total_sequence; if(total_sequence > 0) { // Average error rates dst->seq_err = (dst->seq_err * dst->total_sequence + src->seq_err * src->total_sequence) / total_sequence; // Update mean read length size_t src_num_contigs = 0; if(src->total_sequence && src->mean_read_length) src_num_contigs = ((double)src->total_sequence/src->mean_read_length)+0.5; graph_info_update_contigs(dst, src->total_sequence, src_num_contigs); } // Update error cleaning error_cleaning_merge(&dst->cleaning, &src->cleaning); dst->total_sequence = total_sequence; }
static void json_append_object(lua_State *l, struct luaL_serializer *cfg, int current_depth, strbuf_t *json) { int comma; /* Object */ strbuf_append_char(json, '{'); lua_pushnil(l); /* table, startkey */ comma = 0; while (lua_next(l, -2) != 0) { if (comma) strbuf_append_char(json, ','); else comma = 1; struct luaL_field field; luaL_checkfield(l, cfg, -2, &field); if (field.type == MP_UINT) { strbuf_append_char(json, '"'); json_append_uint(cfg, json, field.ival); strbuf_append_mem(json, "\":", 2); } else if (field.type == MP_INT) { strbuf_append_char(json, '"'); json_append_int(cfg, json, field.ival); strbuf_append_mem(json, "\":", 2); } else if (field.type == MP_STR) { json_append_string(cfg, json, field.sval.data, field.sval.len); strbuf_append_char(json, ':'); } else { luaL_error(l, "table key must be a number or string"); } /* table, key, value */ json_append_data(l, cfg, current_depth + 1, json); lua_pop(l, 1); /* table, key */ } strbuf_append_char(json, '}'); }
lwan_tpl_chunk_t * lwan_tpl_apply_until(lwan_tpl_chunk_t *chunks, strbuf_t *buf, char *(*var_get)(const char *name, void *data), void *var_get_data, bool (*until)(lwan_tpl_chunk_t *chunk, void *data), void *until_data) { lwan_tpl_chunk_t *chunk = chunks; for (; chunk; chunk = chunk->next) { if (until(chunk, until_data)) break; switch (chunk->action) { case TPL_ACTION_APPEND: strbuf_append_str(buf, chunk->data, 0); break; case TPL_ACTION_APPEND_CHAR: strbuf_append_char(buf, (char)(uintptr_t)chunk->data); break; case TPL_ACTION_VARIABLE: { char *tmp = var_get((const char*)chunk->data, var_get_data); strbuf_append_str(buf, tmp, 0); free(tmp); } break; case TPL_ACTION_LIST_START_ITER: strbuf_append_str(buf, "[begin_iter:", 0); strbuf_append_str(buf, chunk->data, 0); strbuf_append_str(buf, "]", 0); break; case TPL_ACTION_LIST_END_ITER: strbuf_append_str(buf, "[end_iter:", 0); strbuf_append_str(buf, chunk->data, 0); strbuf_append_str(buf, "]", 0); break; case TPL_ACTION_IF_VARIABLE_NOT_EMPTY: { const char *var_name = (const char*)chunk->data; char *tmp = var_get(var_name, var_get_data); if (tmp && *tmp) { chunk = lwan_tpl_apply_until(chunk->next, buf, var_get, var_get_data, until_not_empty, chunk->data); } else { for (chunk = chunk->next; chunk; chunk = chunk->next) { if (chunk->action == TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY && !strcmp(chunk->data, var_name)) break; } } free(tmp); } break; case TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY: /* Shouldn't happen */ break; case TPL_ACTION_APPLY_TPL: { strbuf_t *tmp = lwan_tpl_apply(chunk->data, var_get, var_get_data); strbuf_append_str(buf, strbuf_get_buffer(tmp), strbuf_get_length(tmp)); strbuf_free(tmp); } } } return chunk; }
// caller is reposible for freeing *product* and *version* static void parse_release(const char *release, char** product, char** version, int flags) { /* Fedora has a single non-numeric release - Rawhide */ if (strstr(release, "Rawhide")) { *product = xstrdup("Fedora"); *version = xstrdup("rawhide"); log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product); return; } /* openSUSE has two non-numeric releases - Factory and Tumbleweed None of them is unfortunately identified in any of /etc/SuSE-brand, /etc/SuSE-release or /etc/os-release. Keep this piece of code commented just not to forget about that. */ /* if (strstr(release, "Factory")) { *product = xstrdup("openSUSE"); *version = xstrdup("Factory"); log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product); return; } if (strstr(release, "Tumbleweed")) { *product = xstrdup("openSUSE"); *version = xstrdup("Tumbleweed"); log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product); return; } */ bool it_is_rhel = false; struct strbuf *buf_product = strbuf_new(); if (strstr(release, "Fedora")) { strbuf_append_str(buf_product, "Fedora"); } else if (strstr(release, "Red Hat Enterprise Linux")) { strbuf_append_str(buf_product, "Red Hat Enterprise Linux"); it_is_rhel = true; } else if (strstr(release, "openSUSE")) { strbuf_append_str(buf_product, "openSUSE"); } else { /* TODO: add logic for parsing other distros' names here */ strbuf_append_str(buf_product, release); } /* Examples of release strings: * installed system: "Red Hat Enterprise Linux Server release 6.2 Beta (Santiago)" * anaconda: "Red Hat Enterprise Linux 6.2" */ struct strbuf *buf_version = strbuf_new(); const char *r = strstr(release, "release"); const char *space = r ? strchr(r, ' ') : NULL; if (!space) { /* Try to find "<space><digit>" sequence */ space = release; while ((space = strchr(space, ' ')) != NULL) { if (space[1] >= '0' && space[1] <= '9') break; space++; } } if (space) { space++; /* Observed also: "Fedora 16-Alpha" rhbz#730887 */ while ((*space >= '0' && *space <= '9') || *space == '.') { /* Eat string like "5.2" */ strbuf_append_char(buf_version, *space); space++; } if (flags & RETAIN_ALPHA_BETA_TAIL_IN_VER) { /* Example: "... 6.2 [Beta ](Santiago)". * 'space' variable points to non-digit char after "2". * We assume that non-parenthesized text is "Alpha"/"Beta"/etc. * If this text is only whitespace, we won't append it. */ const char *to_append = space; while (*space && *space != '(') /* go to '(' */ space++; while (space > to_append && space[-1] == ' ') /* back to 1st non-space */ space--; strbuf_append_strf(buf_version, "%.*s", (int)(space - to_append), to_append); } } if ((flags & APPEND_MAJOR_VER_TO_RHEL_PRODUCT) && it_is_rhel) { char *v = buf_version->buf; /* Append "integer part" of version to product: * "10.2<anything>" -> append " 10" * "10 <anything>" -> append " 10" * "10" -> append " 10" * "10abcde" -> append ????? */ unsigned idx_dot = strchrnul(v, '.') - v; unsigned idx_space = strchrnul(v, ' ') - v; strbuf_append_strf(buf_product, " %.*s", (idx_dot < idx_space ? idx_dot : idx_space), v ); } *version = strbuf_free_nobuf(buf_version); *product = strbuf_free_nobuf(buf_product); log_debug("%s: version:'%s' product:'%s'", __func__, *version, *product); }
char *make_description(problem_data_t *problem_data, char **names_to_skip, unsigned max_text_size, unsigned desc_flags) { struct strbuf *buf_dsc = strbuf_new(); const char *analyzer = problem_data_get_content_or_NULL(problem_data, FILENAME_ANALYZER); GList *list = g_hash_table_get_keys(problem_data); list = g_list_sort(list, (GCompareFunc)strcmp); GList *l; /* Print one-liners. Format: * NAME1: <maybe more spaces>VALUE1 * NAME2: <maybe more spaces>VALUE2 */ bool empty = true; l = list; while (l) { const char *key = l->data; l = l->next; /* Skip items we are not interested in */ //TODO: optimize by doing this once, not 3 times: if (names_to_skip && rejected_name(key, names_to_skip, desc_flags)) continue; struct problem_item *item = g_hash_table_lookup(problem_data, key); if (!item) continue; if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST)) continue; if ((item->flags & CD_FLAG_TXT) && strlen(item->content) <= max_text_size ) { char *formatted = problem_item_format(item); char *output = formatted ? formatted : item->content; char *eol = strchr(output, '\n'); if (!eol) { int pad = 16 - (strlen(key) + 2); if (pad < 0) pad = 0; strbuf_append_strf(buf_dsc, "%s: %*s%s\n", key, pad, "", output); empty = false; } free(formatted); } } bool append_empty_line = !empty; if (desc_flags & MAKEDESC_SHOW_FILES) { /* Print file info. Format: * <empty line if needed> * NAME1: <maybe more spaces>Binary file, NNN bytes * NAME2: <maybe more spaces>Text file, NNN bytes * * In many cases, it is useful to know how big binary files are * (for example, helps with diagnosing bug upload problems) */ l = list; while (l) { const char *key = l->data; l = l->next; /* Skip items we are not interested in */ if (names_to_skip && rejected_name(key, names_to_skip, desc_flags)) continue; struct problem_item *item = g_hash_table_lookup(problem_data, key); if (!item) continue; if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST)) continue; if ((item->flags & CD_FLAG_BIN) || ((item->flags & CD_FLAG_TXT) && strlen(item->content) > max_text_size) ) { if (append_empty_line) strbuf_append_char(buf_dsc, '\n'); append_empty_line = false; struct stat statbuf; int stat_err = 0; if (item->flags & CD_FLAG_BIN) stat_err = stat(item->content, &statbuf); else statbuf.st_size = strlen(item->content); /* We don't print item->content for CD_FLAG_BIN, as it is * always "/path/to/dump/dir/KEY" - not informative. */ int pad = 16 - (strlen(key) + 2); if (pad < 0) pad = 0; strbuf_append_strf(buf_dsc, (!stat_err ? "%s: %*s%s file, %llu bytes\n" : "%s: %*s%s file\n"), key, pad, "", ((item->flags & CD_FLAG_BIN) ? "Binary" : "Text"), (long long)statbuf.st_size ); empty = false; } } } if (desc_flags & MAKEDESC_SHOW_MULTILINE) { /* Print multi-liners. Format: * <empty line if needed> * NAME: * :LINE1 * :LINE2 * :LINE3 */ l = list; while (l) { const char *key = l->data; l = l->next; /* Skip items we are not interested in */ if (names_to_skip && rejected_name(key, names_to_skip, desc_flags)) continue; struct problem_item *item = g_hash_table_lookup(problem_data, key); if (!item) continue; if ((desc_flags & MAKEDESC_SHOW_ONLY_LIST) && !(item->flags & CD_FLAG_LIST)) continue; if ((item->flags & CD_FLAG_TXT) && (strlen(item->content) <= max_text_size || (!strcmp(analyzer, "Kerneloops") && !strcmp(key, FILENAME_BACKTRACE)))) { char *formatted = problem_item_format(item); char *output = make_description_item_multiline(key, formatted ? formatted : item->content); if (output) { if (!empty) strbuf_append_str(buf_dsc, "\n"); strbuf_append_str(buf_dsc, output); empty = false; free(output); } free(formatted); } } } g_list_free(list); return strbuf_free_nobuf(buf_dsc); }
/* Quote STRING with double quotes if QUOTED is true, otherwise * by escaping whitespace, double quote and backslash as well * as characters in QC. Also, if the first character in STRING * is found in LEADING_QC, that character will be escaped. */ char * quote_word_full(const char *string, bool quoted, bool add_end_quote, const char *qc, const char *leading_qc, bool quote_non_print_hex, bool quote_non_print_oct, bool quote_non_print_c, bool quote_wc) { StrBuf *r = strbuf_new(); const char *s; const unsigned char *u_s; if (quoted) { strbuf_append_char(r, '"'); for (s = string; *s != '\0'; s++) { if (quote_non_print_c) { int chr = 0; switch (*s) { case '\a': chr = 'a'; break; case '\b': chr = 'b'; break; case '\f': chr = 'f'; break; case '\n': chr = 'n'; break; case '\r': chr = 'r'; break; case '\t': chr = 't'; break; case '\v': chr = 'v'; break; } if (chr != 0) { strbuf_appendf(r, "\\%c", chr); continue; } } u_s = (const unsigned char *)s; if (quote_non_print_hex && !isprint(*u_s)) { strbuf_appendf(r, "\\x%02x", (unsigned)*s); } else if (quote_non_print_oct && !isprint(*u_s)) { strbuf_appendf(r, "\\%03o", (unsigned)*s); } else { if (*s == '"' || *s == '\\') strbuf_append_char(r, '\\'); strbuf_append_char(r, *s); } } if (add_end_quote) strbuf_append_char(r, '"'); } else { for (s = string; *s != '\0'; s++) { if (quote_non_print_c) { int chr = 0; switch (*s) { case '\a': chr = 'a'; break; case '\b': chr = 'b'; break; case '\f': chr = 'f'; break; case '\n': chr = 'n'; break; case '\r': chr = 'r'; break; case '\t': chr = 't'; break; case '\v': chr = 'v'; break; } if (chr != 0) { strbuf_appendf(r, "\\%c", chr); continue; } } u_s = (const unsigned char *)s; if (quote_non_print_hex && !isprint(*u_s)) { strbuf_appendf(r, "\\x%02x", (unsigned)*s); } else if (quote_non_print_oct && !isprint(*u_s)) { strbuf_appendf(r, "\\%03o", (unsigned)*u_s); } else { if (*s == '"' || *s == '\\' || (quote_wc && *s == ' ') || strchr(qc, *s) != NULL || (s == string && strchr(leading_qc, *u_s) != NULL)) strbuf_append_char(r, '\\'); strbuf_append_char(r, *s); } } } return strbuf_free_to_string(r); }
// Potential bubble - filter ref and duplicate alleles static void print_bubble(BubbleCaller *caller, GCacheStep **steps, size_t num_paths) { const BubbleCallingPrefs prefs = caller->prefs; const dBGraph *db_graph = caller->db_graph; GCacheSnode *snode; size_t i; dBNodeBuffer *flank5p = &caller->flank5p; if(flank5p->len == 0) { // Haven't fetched 5p flank yet // flank5p[0] already contains the first node flank5p->len = 1; supernode_extend(flank5p, prefs.max_flank_len, db_graph); db_nodes_reverse_complement(flank5p->b, flank5p->len); } // // Print Bubble // // write to string buffer then flush to gzFile StrBuf *sbuf = &caller->output_buf; strbuf_reset(sbuf); // Temporary node buffer to use dBNodeBuffer *pathbuf = &caller->pathbuf; db_node_buf_reset(pathbuf); // Get bubble number (threadsafe num_bubbles_ptr++) size_t id = __sync_fetch_and_add((volatile size_t*)caller->num_bubbles_ptr, 1); // This can be set to anything without a '.' in it const char prefix[] = "call"; // 5p flank // strbuf_sprintf(sbuf, ">bubble.%s%zu.5pflank kmers=%zu\n", prefix, id, flank5p->len); strbuf_append_str(sbuf, ">bubble."); strbuf_append_str(sbuf, prefix); strbuf_append_ulong(sbuf, id); strbuf_append_str(sbuf, ".5pflank kmers="); strbuf_append_ulong(sbuf, flank5p->len); strbuf_append_char(sbuf, '\n'); branch_to_str(flank5p->b, flank5p->len, true, sbuf, db_graph); // 3p flank db_node_buf_reset(pathbuf); snode = graph_cache_snode(&caller->cache, steps[0]->supernode); graph_cache_snode_fetch_nodes(&caller->cache, snode, steps[0]->orient, pathbuf); // strbuf_sprintf(sbuf, ">bubble.%s%zu.3pflank kmers=%zu\n", prefix, id, pathbuf->len); strbuf_append_str(sbuf, ">bubble."); strbuf_append_str(sbuf, prefix); strbuf_append_ulong(sbuf, id); strbuf_append_str(sbuf, ".3pflank kmers="); strbuf_append_ulong(sbuf, pathbuf->len); strbuf_append_char(sbuf, '\n'); branch_to_str(pathbuf->b, pathbuf->len, false, sbuf, db_graph); // Print alleles for(i = 0; i < num_paths; i++) { db_node_buf_reset(pathbuf); graph_cache_step_fetch_nodes(&caller->cache, steps[i], pathbuf); // strbuf_sprintf(sbuf, ">bubble.%s%zu.branch.%zu kmers=%zu\n", // prefix, id, i, pathbuf->len); strbuf_append_str(sbuf, ">bubble."); strbuf_append_str(sbuf, prefix); strbuf_append_ulong(sbuf, id); strbuf_append_str(sbuf, ".branch."); strbuf_append_ulong(sbuf, i); strbuf_append_str(sbuf, " kmers="); strbuf_append_ulong(sbuf, pathbuf->len); strbuf_append_char(sbuf, '\n'); branch_to_str(pathbuf->b, pathbuf->len, false, sbuf, db_graph); } strbuf_append_char(sbuf, '\n'); ctx_assert(strlen(sbuf->b) == sbuf->end); // lock, print, unlock pthread_mutex_lock(caller->out_lock); gzwrite(caller->gzout, sbuf->b, sbuf->end); pthread_mutex_unlock(caller->out_lock); }
static char *format_percented_string(const char *str, problem_data_t *pd) { size_t old_pos[MAX_OPT_DEPTH] = { 0 }; int okay[MAX_OPT_DEPTH] = { 1 }; int opt_depth = 1; struct strbuf *result = strbuf_new(); while (*str) { switch (*str) { default: strbuf_append_char(result, *str); str++; break; case '\\': if (str[1]) str++; strbuf_append_char(result, *str); str++; break; case '[': if (str[1] == '[' && opt_depth < MAX_OPT_DEPTH) { old_pos[opt_depth] = result->len; okay[opt_depth] = 1; opt_depth++; str += 2; } else { strbuf_append_char(result, *str); str++; } break; case ']': if (str[1] == ']' && opt_depth > 1) { opt_depth--; if (!okay[opt_depth]) { result->len = old_pos[opt_depth]; result->buf[result->len] = '\0'; } str += 2; } else { strbuf_append_char(result, *str); str++; } break; case '%': ; char *nextpercent = strchr(++str, '%'); if (!nextpercent) { error_msg_and_die("Unterminated %%element%%: '%s'", str - 1); } *nextpercent = '\0'; const problem_item *item = problem_data_get_item_or_NULL(pd, str); *nextpercent = '%'; if (item && (item->flags & CD_FLAG_TXT)) strbuf_append_str(result, item->content); else okay[opt_depth - 1] = 0; str = nextpercent + 1; break; } } if (opt_depth > 1) { error_msg_and_die("Unbalanced [[ ]] bracket"); } if (!okay[0]) { error_msg("Undefined variable outside of [[ ]] bracket"); } return strbuf_free_nobuf(result); }
static bcf_hdr_t* make_vcf_hdr(cJSON *json, const char *in_path, bool is_breakpoint, size_t kmer_size, char const*const* ref_paths, size_t nref_paths, read_t *chroms, size_t nchroms) { ctx_assert(json != NULL); StrBuf hdrbuf; strbuf_alloc(&hdrbuf, 1024); char datestr[9]; time_t date = time(NULL); strftime(datestr, 9, "%Y%m%d", localtime(&date)); strbuf_append_str(&hdrbuf, "##fileformat=VCFv4.2\n##fileDate="); strbuf_append_str(&hdrbuf, datestr); strbuf_append_str(&hdrbuf, "\n"); // Print commands used to generate header cJSON *commands = json_hdr_get(json, "commands", cJSON_Array, in_path); cJSON *command = commands->child; // Print this command char keystr[8]; char *prevstr = NULL; size_t i; if(command) { cJSON *key = json_hdr_get(command, "key", cJSON_String, in_path); prevstr = key->valuestring; } // Print command entry for this command strbuf_append_str(&hdrbuf, "##mccortex_"); strbuf_append_str(&hdrbuf, hex_rand_str(keystr, sizeof(keystr))); strbuf_append_str(&hdrbuf, "=<prev=\""); strbuf_append_str(&hdrbuf, prevstr ? prevstr : "NULL"); strbuf_append_str(&hdrbuf, "\",cmd=\""); strbuf_append_str(&hdrbuf, cmd_get_cmdline()); strbuf_append_str(&hdrbuf, "\",cwd=\""); strbuf_append_str(&hdrbuf, cmd_get_cwd()); strbuf_append_str(&hdrbuf, "\",version="CTX_VERSION">\n"); // Print previous commands vcf_hdrtxt_append_commands(command, &hdrbuf, in_path); // Print field definitions if(is_breakpoint) strbuf_append_str(&hdrbuf, "##INFO=<ID=BRKPNT,Number=1,Type=String,Description=\"Breakpoint call\">\n"); else strbuf_append_str(&hdrbuf, "##INFO=<ID=BUBBLE,Number=1,Type=String,Description=\"Bubble call\">\n"); strbuf_sprintf(&hdrbuf, "##INFO=<ID=K%zu,Number=0,Type=Flag,Description=\"Found at k=%zu\">\n", kmer_size, kmer_size); strbuf_append_str(&hdrbuf, "##FORMAT=<ID=GT,Number=1,Type=String,Description=\"Genotype\">\n"); strbuf_append_str(&hdrbuf, "##FILTER=<ID=PASS,Description=\"All filters passed\">\n"); // Print reference paths strbuf_append_str(&hdrbuf, "##reference="); strbuf_append_str(&hdrbuf, ref_paths[0]); for(i = 1; i < nref_paths; i++) { strbuf_append_char(&hdrbuf, ','); strbuf_append_str(&hdrbuf, ref_paths[i]); } strbuf_append_str(&hdrbuf, "\n"); // Print contigs lengths for(i = 0; i < nchroms; i++) { strbuf_sprintf(&hdrbuf, "##contig=<ID=%s,length=%zu>\n", chroms[i].name.b, chroms[i].seq.end); } // Print VCF column header strbuf_append_str(&hdrbuf, "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT"); if(is_breakpoint) { // Print a column for each sample cJSON *graph_json = json_hdr_get(json, "graph", cJSON_Object, in_path); cJSON *colours_json = json_hdr_get(graph_json, "colours", cJSON_Array, in_path); cJSON *colour_json = colours_json->child; if(colour_json == NULL) die("Missing colours"); for(; colour_json; colour_json = colour_json->next) { if(!json_hdr_colour_is_ref(colour_json)) { cJSON *sample_json = json_hdr_get(colour_json, "sample", cJSON_String, in_path); strbuf_append_str(&hdrbuf, "\t"); strbuf_append_str(&hdrbuf, sample_json->valuestring); } } } strbuf_append_char(&hdrbuf, '\n'); bcf_hdr_t *hdr = bcf_hdr_init("w"); if(bcf_hdr_parse(hdr, hdrbuf.b) != 0) die("Cannot construct VCF header"); strbuf_dealloc(&hdrbuf); return hdr; }
static void *parse_key_value(struct parser *parser) { struct config_line line = { .type = CONFIG_LINE_TYPE_LINE }; struct lexeme *lexeme; size_t key_size; while (lexeme_buffer_consume(&parser->buffer, &lexeme)) { strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len); if (parser->buffer.population >= 1) strbuf_append_char(&parser->strbuf, '_'); } key_size = strbuf_get_length(&parser->strbuf); strbuf_append_char(&parser->strbuf, '\0'); while (lex_next(&parser->lexer, &lexeme)) { switch (lexeme->type) { case LEXEME_VARIABLE: { const char *value; value = secure_getenv_len(lexeme->value.value, lexeme->value.len); if (!value) { lwan_status_error("Variable '$%.*s' not defined in environment", (int)lexeme->value.len, lexeme->value.value); return NULL; } strbuf_append_str(&parser->strbuf, value, 0); break; } case LEXEME_EQUAL: strbuf_append_char(&parser->strbuf, '='); break; case LEXEME_STRING: strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len); break; case LEXEME_CLOSE_BRACKET: backup(&parser->lexer); /* fallthrough */ case LEXEME_LINEFEED: line.key = strbuf_get_buffer(&parser->strbuf); line.value = line.key + key_size + 1; if (!config_buffer_emit(&parser->items, &line)) return NULL; return parse_config; default: lwan_status_error("Unexpected token while parsing key-value: %s", lexeme_type_str[lexeme->type]); return NULL; } } lwan_status_error("EOF while parsing key-value"); return NULL; }
unsigned parse_opts(int argc, char **argv, const struct options *opt, const char *usage) { int help = 0; int size = parse_opt_size(opt); const int LONGOPT_OFFSET = 256; struct strbuf *shortopts = strbuf_new(); struct option *longopts = xzalloc(sizeof(longopts[0]) * (size+2)); struct option *curopt = longopts; int ii; for (ii = 0; ii < size; ++ii) { curopt->name = opt[ii].long_name; /*curopt->flag = 0; - xzalloc did it */ if (opt[ii].short_name) curopt->val = opt[ii].short_name; else curopt->val = LONGOPT_OFFSET + ii; switch (opt[ii].type) { case OPTION_BOOL: curopt->has_arg = no_argument; if (opt[ii].short_name) strbuf_append_char(shortopts, opt[ii].short_name); break; case OPTION_INTEGER: case OPTION_STRING: case OPTION_LIST: curopt->has_arg = required_argument; if (opt[ii].short_name) strbuf_append_strf(shortopts, "%c:", opt[ii].short_name); break; case OPTION_OPTSTRING: curopt->has_arg = optional_argument; if (opt[ii].short_name) strbuf_append_strf(shortopts, "%c::", opt[ii].short_name); break; case OPTION_GROUP: case OPTION_END: break; } //log("curopt[%d].name:'%s' .has_arg:%d .flag:%p .val:%d", (int)(curopt-longopts), // curopt->name, curopt->has_arg, curopt->flag, curopt->val); /* * getopt_long() thinks that NULL name marks the end of longopts. * Example: * [0] name:'verbose' val:'v' * [1] name:NULL val:'c' * [2] name:'force' val:'f' * ... ... ... * In this case, --force won't be accepted! * Therefore we can only advance if name is not NULL. */ if (curopt->name) curopt++; } curopt->name = "help"; curopt->has_arg = no_argument; curopt->flag = &help; curopt->val = 1; /* xzalloc did it already: curopt++; curopt->name = NULL; curopt->has_arg = 0; curopt->flag = NULL; curopt->val = 0; */ unsigned retval = 0; while (1) { int c = getopt_long(argc, argv, shortopts->buf, longopts, NULL); if (c == -1) break; if (c == '?' || help) { free(longopts); strbuf_free(shortopts); xfunc_error_retval = 0; /* this isn't error, exit code = 0 */ show_usage_and_die(usage, opt); } for (ii = 0; ii < size; ++ii) { if (opt[ii].short_name == c || LONGOPT_OFFSET + ii == c) { if (ii < sizeof(retval)*8) retval |= (1 << ii); if (opt[ii].value != NULL) switch (opt[ii].type) { case OPTION_BOOL: *(int*)(opt[ii].value) += 1; break; case OPTION_INTEGER: *(int*)(opt[ii].value) = xatoi(optarg); break; case OPTION_STRING: case OPTION_OPTSTRING: if (optarg) *(char**)(opt[ii].value) = (char*)optarg; break; case OPTION_LIST: *(GList**)(opt[ii].value) = g_list_append(*(GList**)(opt[ii].value), optarg); break; case OPTION_GROUP: case OPTION_END: break; } } } } free(longopts); strbuf_free(shortopts); return retval; }
lwan_tpl_t * lwan_tpl_compile(const char *filename) { lwan_tpl_t *tpl; strbuf_t *buf; FILE *file; int state = STATE_DEFAULT; char error_msg[512]; tpl = calloc(1, sizeof(*tpl)); if (!tpl) return NULL; buf = strbuf_new(); if (!buf) { free(tpl); return NULL; } file = fopen(filename, "r"); if (!file) { strbuf_free(buf); free(tpl); return NULL; } int line = 1; int column = 1; char ch; while ((ch = fgetc(file)) != EOF) { if (ch == '\n') { if (state == STATE_DEFAULT) strbuf_append_char(buf, '\n'); line++; column = 1; continue; } ++column; switch (state) { case STATE_DEFAULT: if (ch == '{') { state = STATE_FIRST_BRACE; continue; } strbuf_append_char(buf, ch); break; case STATE_FIRST_BRACE: if (ch == '{') { switch (compile_append_text(tpl, buf)) { case -ENOMEM: PARSE_ERROR("Out of memory while appending text."); } state = STATE_SECOND_BRACE; continue; } strbuf_append_char(buf, '{'); strbuf_append_char(buf, ch); state = STATE_DEFAULT; break; case STATE_SECOND_BRACE: if (ch == '{') PARSE_ERROR("Unexpected open brace."); if (ch == '}') { state = STATE_FIRST_CLOSING_BRACE; continue; } strbuf_append_char(buf, ch); break; case STATE_FIRST_CLOSING_BRACE: if (ch == '}') { state = STATE_SECOND_CLOSING_BRACE; continue; } PARSE_ERROR("Closing brace expected."); case STATE_SECOND_CLOSING_BRACE: if (ch == '}') PARSE_ERROR("Unexpected close brace."); if (strbuf_get_length(buf) == 0) PARSE_ERROR("Expecting variable name."); switch (compile_append_var(tpl, buf)) { case -ENOMEM: PARSE_ERROR("Out of memory while appending variable."); case -ENOENT: PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf) + 1); } if (ch == '{') { state = STATE_FIRST_BRACE; continue; } strbuf_append_char(buf, ch); state = STATE_DEFAULT; } } switch (state) { case STATE_DEFAULT: switch (compile_append_text(tpl, buf)) { case -ENOMEM: PARSE_ERROR("Out of memory while appending text."); } break; case STATE_FIRST_BRACE: case STATE_SECOND_BRACE: PARSE_ERROR("Expecting close brace."); case STATE_FIRST_CLOSING_BRACE: PARSE_ERROR("Expecting second close brace."); case STATE_SECOND_CLOSING_BRACE: if (strbuf_get_length(buf) == 0) PARSE_ERROR("Expecting variable name."); switch (compile_append_var(tpl, buf)) { case -ENOMEM: PARSE_ERROR("Out of memory while appending variable."); case -ENOENT: PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf)); } } lwan_tpl_chunk_t *last = malloc(sizeof(*last)); if (!last) goto error; last->action = TPL_ACTION_LAST; last->data = NULL; last->next = tpl->chunks; tpl->chunks = last; lwan_tpl_chunk_t *prev = NULL; while (tpl->chunks) { lwan_tpl_chunk_t *next = tpl->chunks->next; tpl->chunks->next = prev; prev = tpl->chunks; tpl->chunks = next; } tpl->chunks = prev; strbuf_free(buf); return tpl; error: lwan_tpl_free(tpl); strbuf_free(buf); fclose(file); printf("Line %d, column %d: %s\n", line, column, error_msg); return NULL; }
// @param vcf_pos is 0-based // @param prev_base is -1 if SNP otherwise previous base // @param next_base is -1 unless indel at position 0 static void print_vcf_entry(size_t vcf_pos, int8_t prev_base, int8_t next_base, const char *ref, const char *alt, size_t len, const uint8_t *gts, size_t nsamples, CallDecomp *dc, const AlignedCall *call, size_t max_allele_len) { dc->stats.nvars++; StrBuf *sbuf = &dc->sbuf; strbuf_reset(sbuf); // Check actual allele length size_t i, alt_bases = 0; for(i = 0; i < len; i++) alt_bases += (alt[i] != '-'); if(alt_bases > max_allele_len) { dc->stats.nallele_too_long++; return; } // CHROM POS ID REF ALT QUAL FILTER INFO strbuf_append_str(sbuf, call->chrom->name.b); strbuf_append_char(sbuf, '\t'); strbuf_append_ulong(sbuf, vcf_pos+1); strbuf_append_str(sbuf, "\t.\t"); print_vcf_allele(ref, len, prev_base, next_base, sbuf); strbuf_append_char(sbuf, '\t'); print_vcf_allele(alt, len, prev_base, next_base, sbuf); strbuf_append_str(sbuf, "\t.\tPASS\t"); strbuf_append_str(sbuf, call->info.b ? call->info.b : "."); strbuf_append_str(sbuf, "\tGT"); // Print genotypes for(i = 0; i < nsamples; i++) { strbuf_append_char(sbuf, '\t'); strbuf_append_char(sbuf, gts[i] ? '1' : '.'); } strbuf_append_char(sbuf, '\n'); // fprintf(stderr, " prev_base:%i next_base:%i info:%s\n", prev_base, next_base, call->info.b); // fprintf(stderr, "%s [%zu vs %zu]\n", sbuf->b, sbuf->end, strlen(sbuf->b)); kstring_t ks = {.l = sbuf->end, .m = sbuf->size, .s = sbuf->b}; if(vcf_parse(&ks, dc->vcfhdr, dc->v) != 0) die("Cannot construct VCF entry: %s", sbuf->b); if(bcf_write(dc->vcffh, dc->vcfhdr, dc->v) != 0) die("Cannot write VCF entry [nsamples: %zu vs %zu]", nsamples, (size_t)bcf_hdr_nsamples(dc->vcfhdr)); // Move back into our string buffer sbuf->b = ks.s; sbuf->size = ks.m; dc->stats.nvars_printed++; } // `ref` and `alt` are aligned alleles - should both be same length strings // of 'ACGT-' // return first mismatch position or -1 static int align_get_start(const char *ref, const char *alt) { const char *start = ref; while(*ref) { if(*ref != *alt) return (ref - start); ref++; alt++; } return -1; } // `ref` and `alt` are aligned alleles - should both be same length strings // of 'ACGT-' // return first matching position static int align_get_end(const char *ref, const char *alt) { int i = 0; while(ref[i] && ref[i] != alt[i]) i++; return i; }
/** * Print paths to a string buffer. Paths are sorted before being written. * * @param hkey All paths associated with hkey are written to the buffer * @param sbuf paths are written this string buffer * @param subset is a temp variable that is reused each time * @param nbuf temporary buffer, if not NULL, used to add seq=... to output * @param jposbuf temporary buffer, if not NULL, used to add juncpos=... to output */ void gpath_save_sbuf(hkey_t hkey, StrBuf *sbuf, GPathSubset *subset, dBNodeBuffer *nbuf, SizeBuffer *jposbuf, const dBGraph *db_graph) { ctx_assert(db_graph->num_of_cols == 1 || nbuf == NULL); ctx_assert(db_graph->num_of_cols == 1 || jposbuf == NULL); const GPathStore *gpstore = &db_graph->gpstore; const GPathSet *gpset = &gpstore->gpset; const size_t ncols = gpstore->gpset.ncols; GPath *first_gpath = gpath_store_fetch(gpstore, hkey); const GPath *gpath; size_t i, j, col; // Load and sort paths for given kmer gpath_subset_reset(subset); gpath_subset_load_llist(subset, first_gpath); gpath_subset_sort(subset); if(subset->list.len == 0) return; // Print "<kmer> <npaths>" BinaryKmer bkmer = db_graph->ht.table[hkey]; char bkstr[MAX_KMER_SIZE+1]; binary_kmer_to_str(bkmer, db_graph->kmer_size, bkstr); // strbuf_sprintf(sbuf, "%s %zu\n", bkstr, subset->list.len); strbuf_append_strn(sbuf, bkstr, db_graph->kmer_size); strbuf_append_char(sbuf, ' '); strbuf_append_ulong(sbuf, subset->list.len); strbuf_append_char(sbuf, '\n'); char orchar[2] = {0}; orchar[FORWARD] = 'F'; orchar[REVERSE] = 'R'; const uint8_t *nseenptr; for(i = 0; i < subset->list.len; i++) { gpath = subset->list.b[i]; nseenptr = gpath_set_get_nseen(gpset, gpath); // strbuf_sprintf(sbuf, "%c %zu %u %u", orchar[gpath->orient], klen, // gpath->num_juncs, (uint32_t)nseenptr[0]); strbuf_append_char(sbuf, orchar[gpath->orient]); strbuf_append_char(sbuf, ' '); strbuf_append_ulong(sbuf, gpath->num_juncs); strbuf_append_char(sbuf, ' '); strbuf_append_ulong(sbuf, nseenptr[0]); for(col = 1; col < ncols; col++) { // strbuf_sprintf(sbuf, ",%u", (uint32_t)nseenptr[col]); strbuf_append_char(sbuf, ','); strbuf_append_ulong(sbuf, nseenptr[col]); } strbuf_append_char(sbuf, ' '); strbuf_ensure_capacity(sbuf, sbuf->end + gpath->num_juncs + 2); binary_seq_to_str(gpath->seq, gpath->num_juncs, sbuf->b+sbuf->end); sbuf->end += gpath->num_juncs; if(nbuf) { // Trace this path through the graph // First, find a colour this path is in for(col = 0; col < ncols && !gpath_has_colour(gpath, ncols, col); col++) {} if(col == ncols) die("path is not in any colours"); dBNode node = {.key = hkey, .orient = gpath->orient}; db_node_buf_reset(nbuf); if(jposbuf) size_buf_reset(jposbuf); // indices of junctions in nbuf gpath_fetch(node, gpath, nbuf, jposbuf, col, db_graph); strbuf_append_str(sbuf, " seq="); strbuf_ensure_capacity(sbuf, sbuf->end + db_graph->kmer_size + nbuf->len); sbuf->end += db_nodes_to_str(nbuf->b, nbuf->len, db_graph, sbuf->b+sbuf->end); if(jposbuf) { strbuf_append_str(sbuf, " juncpos="); strbuf_append_ulong(sbuf, jposbuf->b[0]); for(j = 1; j < jposbuf->len; j++) { strbuf_append_char(sbuf, ','); strbuf_append_ulong(sbuf, jposbuf->b[j]); } } } strbuf_append_char(sbuf, '\n'); } } // @subset is a temp variable that is reused each time // @sbuf is a temp variable that is reused each time static inline int _gpath_gzsave_node(hkey_t hkey, StrBuf *sbuf, GPathSubset *subset, dBNodeBuffer *nbuf, SizeBuffer *jposbuf, gzFile gzout, pthread_mutex_t *outlock, const dBGraph *db_graph) { gpath_save_sbuf(hkey, sbuf, subset, nbuf, jposbuf, db_graph); if(sbuf->end > DEFAULT_IO_BUFSIZE) _gpath_save_flush(gzout, sbuf, outlock); return 0; // => keep iterating }