int dfs_d(const igraph_t *graph, igraph_integer_t root, igraph_neimode_t mode, igraph_bool_t unreachable, igraph_vector_t *order, igraph_vector_t *order_out, igraph_vector_t *father, igraph_vector_t *dist, igraph_dfshandler_t *in_callback, igraph_dfshandler_t *out_callback, void *extra) { long int no_of_nodes=igraph_vcount(graph); igraph_lazy_adjlist_t adjlist; igraph_stack_t stack; igraph_vector_char_t added; igraph_vector_long_t nptr; long int actroot; long int act_rank=0; long int rank_out=0; long int act_dist=0; if (root < 0 || root >= no_of_nodes) { IGRAPH_ERROR("Invalid root vertex for DFS", IGRAPH_EINVAL); } if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE); } if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; } IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_stack_init(&stack, 100)); IGRAPH_FINALLY(igraph_stack_destroy, &stack); IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, /*simplify=*/ 0)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); IGRAPH_CHECK(igraph_vector_long_init(&nptr, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &nptr); # define FREE_ALL() do { \ igraph_vector_long_destroy(&nptr); \ igraph_lazy_adjlist_destroy(&adjlist); \ igraph_stack_destroy(&stack); \ igraph_vector_char_destroy(&added); \ IGRAPH_FINALLY_CLEAN(4); } while (0) /* Resize result vectors and fill them with IGRAPH_NAN */ # define VINIT(v) if (v) { \ igraph_vector_resize(v, no_of_nodes); \ igraph_vector_fill(v, IGRAPH_NAN); } VINIT(order); VINIT(order_out); VINIT(father); VINIT(dist); # undef VINIT IGRAPH_CHECK(igraph_stack_push(&stack, root)); VECTOR(added)[(long int)root] = 1; if (father) { VECTOR(*father)[(long int)root] = -1; } if (order) { VECTOR(*order)[act_rank++] = root; } if (dist) { VECTOR(*dist)[(long int)root] = 0; } if (in_callback) { igraph_bool_t terminate=in_callback(graph, root, 0, extra); if (terminate) { FREE_ALL(); return 0; } } for (actroot=0; actroot<no_of_nodes; actroot++) { /* 'root' first, then all other vertices */ if (igraph_stack_empty(&stack)) { if (!unreachable) { break; } if (VECTOR(added)[actroot]) { continue; } IGRAPH_CHECK(igraph_stack_push(&stack, actroot)); VECTOR(added)[actroot] = 1; if (father) { VECTOR(*father)[actroot] = -1; } if (order) { VECTOR(*order)[act_rank++] = actroot; } if (dist) { VECTOR(*dist)[actroot] = 0; } if (in_callback) { igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) actroot, 0, extra); if (terminate) { FREE_ALL(); return 0; } } } while (!igraph_stack_empty(&stack)) { long int actvect=(long int) igraph_stack_top(&stack); igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) actvect); long int n=igraph_vector_size(neis); long int *ptr=igraph_vector_long_e_ptr(&nptr, actvect); igraph_vector_shuffle(neis); igraph_vector_print(neis); /* Search for a neighbor that was not yet visited */ igraph_bool_t any=0; long int nei; while (!any && (*ptr) <n) { nei=(long int) VECTOR(*neis)[(*ptr)]; any=!VECTOR(added)[nei]; (*ptr) ++; } if (any) { /* There is such a neighbor, add it */ IGRAPH_CHECK(igraph_stack_push(&stack, nei)); VECTOR(added)[nei] = 1; if (father) { VECTOR(*father)[ nei ] = actvect; } if (order) { VECTOR(*order)[act_rank++] = nei; } act_dist++; if (dist) { VECTOR(*dist)[nei] = act_dist; } if (in_callback) { igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) nei, (igraph_integer_t) act_dist, extra); if (terminate) { FREE_ALL(); return 0; } } } else { /* There is no such neighbor, finished with the subtree */ igraph_stack_pop(&stack); if (order_out) { VECTOR(*order_out)[rank_out++] = actvect; } act_dist--; if (out_callback) { igraph_bool_t terminate=out_callback(graph, (igraph_integer_t) actvect, (igraph_integer_t) act_dist, extra); if (terminate) { FREE_ALL(); return 0; } } } } } FREE_ALL(); # undef FREE_ALL return 0; }
static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gchar** error) { enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE; GString* out; GString* name = NULL; GString* arg = NULL; GPtrArray* args = NULL; gchar c; const gchar* r = text; gboolean changed = FALSE; if ( depth > 31) { if (error != NULL) *error = g_strdup("too much nesting in macros"); return NULL; } #define FGS(n) if (n) g_string_free(n,TRUE); n = NULL #define FREE_ALL() \ do { \ FGS(name); \ FGS(arg); \ if (args) { \ while(args->len) { void* p = g_ptr_array_remove_index_fast(args,0); if (p) g_free(p); } \ g_ptr_array_free(args,TRUE); \ args = NULL; \ } \ } while(0) if (error != NULL) *error = NULL; out = g_string_sized_new(64); while(1) { c = *r++; switch(state) { case OUTSIDE: { switch(c) { case '\0': { goto finish; } case '$': { state = STARTING; break; } default: { g_string_append_c(out,c); break; } } break; } case STARTING: { switch (c) { case '{': { args = g_ptr_array_new(); arg = g_string_sized_new(32); name = g_string_sized_new(32); state = NAME; break; } case '\0': { g_string_append_c(out,'$'); goto finish; } default: { g_string_append_c(out,'$'); g_string_append_c(out,c); state = OUTSIDE; break; } } break; } case NAME: { if ( g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.' ) { g_string_append_c(name,c); } else if ( c == ':') { state = ARGS; } else if ( c == '}') { gchar* resolved; g_ptr_array_add(args,NULL); resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error); if (resolved == NULL) goto on_error; changed = TRUE; g_string_append(out,resolved); wmem_free(NULL, resolved); FREE_ALL(); state = OUTSIDE; } else if ( c == '\0') { if (error != NULL) *error = g_strdup("end of filter in the middle of a macro expression"); goto on_error; } else { if (error != NULL) *error = g_strdup("invalid character in macro name"); goto on_error; } break; } case ARGS: { switch(c) { case '\0': { if (error != NULL) *error = g_strdup("end of filter in the middle of a macro expression"); goto on_error; } case ';': { g_ptr_array_add(args,g_string_free(arg,FALSE)); arg = g_string_sized_new(32); break; } case '\\': { c = *r++; if (c) { g_string_append_c(arg,c); break; } else { if (error != NULL) *error = g_strdup("end of filter in the middle of a macro expression"); goto on_error; } } default: { g_string_append_c(arg,c); break; } case '}': { gchar* resolved; g_ptr_array_add(args,g_string_free(arg,FALSE)); g_ptr_array_add(args,NULL); arg = NULL; resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error); if (resolved == NULL) goto on_error; changed = TRUE; g_string_append(out,resolved); wmem_free(NULL, resolved); FREE_ALL(); state = OUTSIDE; break; } } break; } } } finish: { FREE_ALL(); if (changed) { gchar* resolved = dfilter_macro_apply_recurse(out->str, depth + 1, error); g_string_free(out,TRUE); return resolved; } else { gchar* out_str = wmem_strdup(NULL, out->str); g_string_free(out,TRUE); return out_str; } } on_error: { FREE_ALL(); if (error != NULL) { if (*error == NULL) *error = g_strdup("unknown error in macro expression"); } g_string_free(out,TRUE); return NULL; } }