Skip to content
Snippets Groups Projects
Commit 6c0d2c78 authored by Eric Vidal's avatar Eric Vidal :speech_balloon:
Browse files

add graph function

parent d9743bea
No related branches found
No related tags found
No related merge requests found
......@@ -20,6 +20,7 @@
#include <66/constants.h>
#include <66/db.h>
#include <66/enum.h>
#include <66/graph.h>
#include <66/parser.h>
#include <66/svc.h>
#include <66/tree.h>
......
/*
* graph.h
*
* Copyright (c) 2018 Eric Vidal <eric@obarun.org>
*
* All rights reserved.
*
* This file is part of Obarun. It is subject to the license terms in
* the LICENSE file found in the top-level directory of this
* distribution.
* This file may not be copied, modified, propagated, or distributed
* except according to the terms contained in the LICENSE file./
*/
#ifndef GRAPH_H
#define GRAPH_H
extern stralloc SAGRAPH ;
typedef enum visit_e visit ;
enum visit_e
{
WHITE = 0,
GRAY,
BLACK
} ;
typedef struct vertex_graph_s vertex_graph_t, *vertex_graph_t_ref ;
struct vertex_graph_s
{
unsigned int type ; //type of the service
unsigned int idx ; //idx of the service
unsigned int name ; //pos in associated stralloc, name of the service
unsigned int ndeps ; //number of dependencies
unsigned int gaidx ; //pos of deps in genalloc dps
genalloc dps ; // type vertex_graph_t
} ;
typedef struct graph_s graph_t, *graph_t_ref ;
struct graph_s
{
unsigned int nvertex ; //number of vertex
unsigned int nedge ; //number of edge
char *string ; // associated stralloc
genalloc vertex ; //type vertex_graph_t
genalloc stack ; //vertex_graph_t, topological sorted
} ;
#define VERTEX_GRAPH_ZERO { 0, 0, 0, 0, 0, GENALLOC_ZERO }
#define GRAPH_ZERO { 0, 0, 0, GENALLOC_ZERO, GENALLOC_ZERO }
static vertex_graph_t const vertex_graph_zero = VERTEX_GRAPH_ZERO ;
static graph_t const graph_zero = GRAPH_ZERO ;
typedef struct tdepth_s tdepth ;
struct tdepth_s
{
tdepth *prev;
tdepth *next;
int level;
unsigned int cndeps ;
unsigned int pndeps ;
} ;
typedef struct graph_style_s graph_style ;
struct graph_style_s
{
const char *tip;
const char *last;
const char *limb;
int indent;
} ;
#define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
#define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
#define UTF_H "\342\224\200" /* U+2500, Horizontal */
#define UTF_UR "\342\224\224" /* U+2514, Up and right */
extern unsigned int MAXDEPTH ;
extern graph_style *STYLE ;
extern graph_style graph_utf8 ;
extern graph_style graph_default ;
/** what = 0 -> only classic
* what = 1 -> only atomic
* what = 2 -> both*/
extern int graph_type_src(genalloc *ga,char const *tree,unsigned int what) ;
extern int graph_build(graph_t *g, stralloc *sagraph, genalloc *tokeep,char const *tree) ;
extern int graph_rdepends(genalloc *ga,graph_t *g, char const *name, char const *src) ;
extern int graph_master(genalloc *ga, graph_t *g) ;
extern int graph_sort(graph_t *g) ;
extern int graph_search(graph_t *g, char const *name) ;
extern int graph_tree(graph_t *g, char const *name, char const *tree) ;
extern void stack_reverse(genalloc *st) ;
#endif
/*
* graph.c
*
* Copyright (c) 2018 Eric Vidal <eric@obarun.org>
*
* All rights reserved.
*
* This file is part of Obarun. It is subject to the license terms in
* the LICENSE file found in the top-level directory of this
* distribution.
* This file may not be copied, modified, propagated, or distributed
* except according to the terms contained in the LICENSE file./
*/
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <oblibs/string.h>
#include <oblibs/error2.h>
#include <oblibs/stralist.h>
#include <oblibs/strakeyval.h>
#include <oblibs/directory.h>
#include <oblibs/files.h>
#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
#include <skalibs/direntry.h>
#include <skalibs/unix-transactional.h>//stat_at
#include <skalibs/lolstdio.h>
#include <66/graph.h>
#include <66/enum.h>
#include <66/utils.h>
#include <66/constants.h>
#include <stdio.h>
graph_style graph_utf8 = {
UTF_VR UTF_H,
UTF_UR UTF_H,
UTF_V " ",
2
} ;
graph_style graph_default = {
"|-",
"`-",
"|",
2
} ;
static void print_text(const char *pkg, const char *info, tdepth *depth, int last)
{
const char *tip = "" ;
int level = 1 ;
if(!pkg)
return ;
if(depth->level > 0)
{
tip = last ? STYLE->last : STYLE->tip;
while(depth->prev)
depth = depth->prev;
while(depth->next)
{
if (!bprintf(buffer_1," %*s%-*s",STYLE->indent * (depth->level - level), "", STYLE->indent, STYLE->limb)) return ;
level = depth->level + 1;
depth = depth->next;
}
}
if(depth->level > 0)
{
if (!bprintf(buffer_1," %*s%s%s ",STYLE->indent * (depth->level - level),"",tip,pkg)) return ;
}
else if (!bprintf(buffer_1," %s%s ",tip,pkg)) return ;
if(info)
if (!bprintf(buffer_1," %s%s", ":",info)) return ;
if (buffer_putsflush(buffer_1,"\n") < 0) return ;
}
static void print(const char *pkgname, const char *depname, tdepth *depth, int last)
{
print_text(pkgname, depname, depth, last);
}
/*
static void print_start(const char *pkgname, const char *provname)
{
tdepth d = {
NULL,
NULL,
0 ,
0 ,
0
};
print_text(pkgname, provname, &d, 0);
}
*/
static void graph_walk(graph_t *g,genalloc *ga,unsigned int src,unsigned int nlen, tdepth *depth)
{
unsigned int last, i, newdata ;
unsigned int stacklen = genalloc_len(vertex_graph_t,ga) ;
if(!stacklen || ((MAXDEPTH >= 0) && (depth->level > MAXDEPTH)))
return ;
char *string = g->string ;
i = src ;
last = newdata = 0 ;
for(; i < stacklen && i < nlen ; i++ )
{
for (unsigned int d = 0 ; d < genalloc_len(vertex_graph_t,&g->stack) ; d++)
{
if (genalloc_s(vertex_graph_t,ga)[i].idx == genalloc_s(vertex_graph_t,&g->stack)[d].idx)
{
newdata = genalloc_s(vertex_graph_t,&g->stack)[d].gaidx ;
break ;
}
else
{
newdata = genalloc_s(vertex_graph_t,ga)[i].gaidx ;
}
}
int idx = genalloc_s(vertex_graph_t,&g->vertex)[newdata].name ;
char *name = string + idx ;
char const *type = get_keybyid(genalloc_s(vertex_graph_t,&g->vertex)[newdata].type) ;
unsigned int dplen = genalloc_s(vertex_graph_t,&g->vertex)[newdata].ndeps ;
last = i + 1 < depth->pndeps ? 0 : 1 ;
print(name, type, depth, last) ;
if (dplen)
{
genalloc data = genalloc_s(vertex_graph_t,&g->vertex)[newdata].dps ;
tdepth d =
{
depth,
NULL,
depth->level + 1 ,
depth->cndeps ,
dplen
} ;
depth->next = &d;
if(last)
{
if(depth->prev)
{
depth->prev->next = &d;
d.prev = depth->prev;
depth = &d;
depth->cndeps = 0 ;
}
else
d.prev = NULL;
}
graph_walk(g,&data,0,dplen,&d);
depth->next = NULL;
depth->cndeps = 0 ;
}
}
}
int graph_tree(graph_t *g, char const *name, char const *tree)
{
unsigned int a = 0 ;
unsigned int first = 0 ;
unsigned int ndeps = g->nvertex ;
//print_start(tree, 0) ;
if (name)
{
char *string = g->string ;
for (; a < g->nvertex ; a++)
{
char *gname = string + genalloc_s(vertex_graph_t,&g->stack)[a].name ;
if (obstr_equal(name,gname))
{
first = a ;
ndeps = first + 1 ;
break ;
}
}
}
tdepth d = {
NULL,
NULL,
1 ,
0 ,
ndeps
} ;
graph_walk(g,&g->stack,first,ndeps,&d);
return 1 ;
}
int stack_init(genalloc *st, unsigned int len)
{
*st = genalloc_zero ;
return genalloc_ready(vertex_graph_t,st,len) ;
}
int stack_push_at(genalloc *st,genalloc *data,unsigned int len, unsigned int idx)
{
return genalloc_insertb(vertex_graph_t,st,idx,&genalloc_s(vertex_graph_t,data)[len],1) ;
}
int stack_push_start(genalloc *st, genalloc *data,unsigned int len)
{
return stack_push_at(st,data,len,0) ;
}
void stack_reverse(genalloc *st)
{
for (unsigned int i = 0 ; i < genalloc_len(vertex_graph_t,st) ; i++)
{
genalloc_reverse(vertex_graph_t,&genalloc_s(vertex_graph_t,st)[i].dps) ;
}
genalloc_reverse(vertex_graph_t,st) ;
}
int stack_push(genalloc *st,genalloc *data,unsigned int len)
{
return genalloc_append(vertex_graph_t,st,&genalloc_s(vertex_graph_t,data)[len]) ;
}
int dfs(graph_t *g, unsigned int idx, genalloc *stack, visit *c)
{
int cycle = 0 ;
unsigned int i, data ;
unsigned int len = genalloc_s(vertex_graph_t,&g->vertex)[idx].ndeps ;
if (c[idx] == GRAY) return 1 ;
if (c[idx] == WHITE)
{
c[idx] = GRAY ;
for (i = 0 ; i < len ; i++)
{
data = genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[idx].dps)[i].gaidx ;
cycle = (cycle || dfs(g,data, stack, c)) ;
}
c[idx] = BLACK ;
stack_push_start(stack,&g->vertex,idx) ;
}
return cycle ;
}
int graph_sort(graph_t *g)
{
unsigned int len = g->nvertex ;
unsigned int color = g->nedge ;
visit c[color] ;
for (unsigned int i = 0 ; i < color; i++) c[i] = WHITE ;
if (!len) return 0 ;
if (!stack_init(&g->stack,color))
{
VERBO3 strerr_warnwu1x("iniate stack") ;
return 0;
}
for (unsigned int i = 0 ; i < len ; i++)
{
if ( c[i] == WHITE && dfs(g,i,&g->stack,c))
{
genalloc_free(vertex_graph_t,&g->stack) ;
return -1 ;
}
}
return 1 ;
}
int graph_master(genalloc *ga, graph_t *g)
{
unsigned int data, ddata,a,b,w ;
unsigned int color = g->nedge ;
visit c[color] ;
for (unsigned int i = 0 ; i < color; i++) c[i] = WHITE ;
char *string = g->string ;
for (a = 0 ; a < genalloc_len(vertex_graph_t,&g->stack) ; a++)
{
data = genalloc_s(vertex_graph_t,&g->stack)[a].idx ;
for (b = 0 ; b < genalloc_len(vertex_graph_t,&g->stack) ; b++)
{
for (unsigned int d = 0 ; d < genalloc_s(vertex_graph_t,&g->stack)[b].ndeps ; d++)
{
ddata = genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->stack)[b].dps)[d].idx ;
if (data == ddata) c[a] = BLACK ;
}
}
}
for (w = 0 ; w < g->nvertex ; w++)
if (c[w] == WHITE)
if (!stra_add(ga,string + genalloc_s(vertex_graph_t,&g->stack)[w].name))
return 0 ;
return 1 ;
}
int graph_rdepends(genalloc *ga,graph_t *g, char const *name, char const *src)
{
unsigned int i,k ;
int r ;
char *string = g->string ;
unsigned int type = graph_search(g,name) ;
/** bundle , we need to check every service set onto it*/
if (genalloc_s(vertex_graph_t,&g->vertex)[type].type == BUNDLE)
{
for (k = 0; k < genalloc_s(vertex_graph_t,&g->vertex)[type].ndeps; k++)
{
char *depname = g->string + genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[type].dps)[k].name ;
if (!stra_cmp(ga,depname))
{
if (!stra_add(ga,depname))
{
VERBO3 strerr_warnwu3x("add: ",depname," as dependency to remove") ;
return 0 ;
}
if (!find_logger(ga,depname,src))
{
VERBO3 strerr_warnwu3x("add: ",gaistr(ga,genalloc_len(stralist,ga)-1)," as dependency to remove") ;
return 0 ;
}
}
r = graph_rdepends(ga,g,depname,src) ;
if (!r)
{
VERBO3 strerr_warnwu2x("find services depending on: ",name) ;
return 0 ;
}
if(r == 2)
{
VERBO3 strerr_warnt2x("any services don't depends on: ",name) ;
return 2 ;
}
}
}
for (i = 0 ; i < g->nvertex ; i++)
{
char *master = string + genalloc_s(vertex_graph_t,&g->vertex)[i].name ;
if (obstr_equal(name,master)) continue ;
if (genalloc_s(vertex_graph_t,&g->vertex)[i].ndeps)
{
for (k = 0; k < genalloc_s(vertex_graph_t,&g->vertex)[i].ndeps; k++)
{
char *depname = string + genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[i].dps)[k].name ;
if (obstr_equal(name,depname))
{
/* if (genalloc_s(vertex_graph_t,&g->vertex)[i].type == BUNDLE)
continue ;*/
if (!stra_cmp(ga,master))
{
if (!stra_add(ga,master))
{
VERBO3 strerr_warnwu3x("add: ",depname," as dependency to remove") ;
return 0 ;
}
if (!find_logger(ga,master,src))
{
VERBO3 strerr_warnwu3x("add: ",gaistr(ga,genalloc_len(stralist,ga)-1)," as dependency to remove") ;
return 0 ;
}
r = graph_rdepends(ga,g,master,src) ;
if (!r) return 0 ;
}
}
}
}
}
if (!genalloc_len(stralist,ga))
{
genalloc_deepfree(stralist,ga,stra_free) ;
return 2 ;
}
return 1 ;
}
/** what = 0 -> only classic
* what = 1 -> only atomic
* what = 2 -> both
* @Return 0 on fail
* @Return -1 for empty graph*/
int graph_type_src(genalloc *ga,char const *dir,unsigned int what)
{
size_t dirlen = strlen(dir) ;
char solve[dirlen + SS_DB_LEN + SS_SRC_LEN + 1] ;
memcpy(solve,dir,dirlen) ;
memcpy(solve + dirlen, SS_SVC, SS_SVC_LEN) ;
solve[dirlen + SS_SVC_LEN] = 0 ;
if (!what || what == 2)
if (!dir_get(ga,solve,SS_MASTER + 1,S_IFDIR)) return 0 ;
memcpy(solve + dirlen, SS_DB, SS_DB_LEN) ;
memcpy(solve + dirlen + SS_DB_LEN, SS_SRC, SS_SRC_LEN) ;
solve[dirlen + SS_DB_LEN + SS_SRC_LEN] = 0 ;
if (what)
if (!dir_get(ga,solve,SS_MASTER + 1,S_IFDIR)) return 0 ;
if (!genalloc_len(stralist,ga)) return -1 ;
return 1 ;
}
int graph_build(graph_t *g, stralloc *sagraph, genalloc *tokeep,char const *dir)
{
size_t dirlen = strlen(dir) ;
size_t newlen = 0 ;
char solve[dirlen + SS_RESOLVE_LEN + 1 + 1] ;
memcpy(solve,dir,dirlen) ;
memcpy(solve + dirlen, SS_RESOLVE,SS_RESOLVE_LEN) ;
solve[dirlen + SS_RESOLVE_LEN] = '/' ;
newlen = dirlen + SS_RESOLVE_LEN + 1 ;
solve[newlen] = 0 ;
genalloc gatmp = GENALLOC_ZERO ;//stralist
stralloc res = STRALLOC_ZERO ;
graph_t gtmp = GRAPH_ZERO ;
vertex_graph_t gsv = VERTEX_GRAPH_ZERO ;
vertex_graph_t gdeps = VERTEX_GRAPH_ZERO ;
unsigned int nvertex = 0 ;
unsigned int nedge = 0 ;
for (unsigned int i = 0 ; i < genalloc_len(stralist,tokeep) ; i++)
{
char *file = "deps" ;
char const *name = gaistr(tokeep,i) ;
size_t namelen = gaistrlen(tokeep,i) ;
char namesrc[newlen + namelen + 1] ;
memcpy(namesrc,solve,newlen) ;
memcpy(namesrc + newlen,name,namelen) ;
namesrc[newlen + namelen] = 0 ;
res = stralloc_zero ;
if (!file_readputsa(&res,namesrc,"type"))
{
VERBO3 strerr_warnwu2x("read type of: ",name) ;
goto err ;
}else gsv.type = get_enumbyid(res.s,key_enum_el) ;
res = stralloc_zero ;
if (file_readputsa(&res,namesrc,file))
{
if (!clean_val(&gatmp,res.s))
{
VERBO3 strerr_warnwu2x("clean val: ",res.s) ;
goto err ;
}
}
/*file = "logger" ;
res = stralloc_zero ;
if(file_readputsa(&res,namesrc,file))
{
if (!clean_val(&gatmp,res.s))
{
VERBO3 strerr_warnwu2x("clean val: ",res.s) ;
goto err ;
}
}*/
gsv.idx = nedge ;
nedge++ ;
gsv.gaidx = genalloc_len(vertex_graph_t, &gtmp.vertex) ;
gsv.name = sagraph->len ;
if (!stralloc_catb(sagraph,name,namelen + 1)) goto err ;
if (genalloc_len(stralist,&gatmp))
{
gsv.ndeps = genalloc_len(stralist,&gatmp) ;
for (unsigned int i = 0 ; i < genalloc_len(stralist,&gatmp);i++)
{
gdeps.idx = nedge++ ;
gdeps.name = sagraph->len ;
if (!stralloc_catb(sagraph,gaistr(&gatmp,i),gaistrlen(&gatmp,i) + 1)) goto err ;
gdeps.gaidx = genalloc_len(vertex_graph_t,&gsv.dps) ;
gdeps.ndeps = 0 ;
gdeps.dps = genalloc_zero ;
if (!genalloc_append(vertex_graph_t,&gsv.dps,&gdeps)) goto err ;
}
}
gtmp.nedge = nedge ;
gtmp.nvertex = ++nvertex ;
if (!genalloc_append(vertex_graph_t,&gtmp.vertex,&gsv)) goto err ;
gsv = vertex_graph_zero ;
gdeps = vertex_graph_zero ;
gatmp = genalloc_zero ;
}
stralloc_free(&res) ;
genalloc_deepfree(stralist,&gatmp,stra_free) ;
/** second pass */
char *string = sagraph->s ;
for (unsigned int a = 0 ; a < gtmp.nvertex ; a++)
{
int idxa = genalloc_s(vertex_graph_t,&gtmp.vertex)[a].idx ;
gsv.idx = idxa ;
gsv.type = genalloc_s(vertex_graph_t,&gtmp.vertex)[a].type ;
gsv.name = genalloc_s(vertex_graph_t,&gtmp.vertex)[a].name ;
gsv.ndeps = genalloc_s(vertex_graph_t,&gtmp.vertex)[a].ndeps ;
gsv.gaidx = genalloc_s(vertex_graph_t,&gtmp.vertex)[a].gaidx ;
for (unsigned int b = 0 ; b < genalloc_s(vertex_graph_t,&gtmp.vertex)[a].ndeps ; b++)
{
int idxb = genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&gtmp.vertex)[a].dps)[b].idx ;
int nb = genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&gtmp.vertex)[a].dps)[b].name ;
char *nameb = string + nb ;
gdeps.gaidx = genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&gtmp.vertex)[a].dps)[b].gaidx ;
gdeps.ndeps = 0 ;
gdeps.dps = genalloc_zero ;
gdeps.idx = idxb ;
gdeps.name = nb ;
for (unsigned int c = 0 ; c < gtmp.nvertex ; c++)
{
int idxc = genalloc_s(vertex_graph_t,&gtmp.vertex)[c].idx ;
if (idxa == idxc) continue ;
int nc = genalloc_s(vertex_graph_t,&gtmp.vertex)[c].name ;
char *namec = string + nc ;
if (obstr_equal(namec,nameb))
{
gdeps.idx = idxc ;
gdeps.name = nc ;
gdeps.gaidx = genalloc_s(vertex_graph_t,&gtmp.vertex)[c].gaidx ;
gdeps.ndeps = genalloc_s(vertex_graph_t,&gtmp.vertex)[c].ndeps ;
gdeps.type = genalloc_s(vertex_graph_t,&gtmp.vertex)[c].type ;
break ;
}
}
if (!genalloc_append(vertex_graph_t,&gsv.dps,&gdeps)) goto err ;
}
if (!genalloc_append(vertex_graph_t,&g->vertex,&gsv)) goto err ;
gsv = vertex_graph_zero ;
gdeps = vertex_graph_zero ;
}
g->string = sagraph->s ;
g->nvertex = gtmp.nvertex ;
g->nedge = gtmp.nedge ;
genalloc_free(vertex_graph_t,&gsv.dps) ;
genalloc_free(vertex_graph_t,&gdeps.dps) ;
/*for (unsigned int i = 0 ; i < genalloc_len(vertex_graph_t,&g->vertex) ; i++)
{
char *string = g->string ;
//int idx = genalloc_s(unsigned int,&g->vertex)[i] ;
printf("i::%i::type::%s\n",i,get_keybyid(genalloc_s(vertex_graph_t,&g->vertex)[i].type)) ;
//printf("i::%i::idx::%i\n",i,genalloc_s(vertex_graph_t,&g->vertex)[i].idx) ;
printf("i::%i::name::%s\n",i,string + genalloc_s(vertex_graph_t,&g->vertex)[i].name) ;
//printf("i::%i::ndeps::%i\n",i,genalloc_s(vertex_graph_t,&g->vertex)[i].ndeps) ;
//printf("i::%i::gaidx::%i\n",i,genalloc_s(vertex_graph_t,&g->vertex)[i].gaidx) ;
for (unsigned int d = 0 ; d < genalloc_s(vertex_graph_t,&g->vertex)[i].ndeps ; d++)
{
printf(" deps type::%s\n", get_keybyid(genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[i].dps)[d].type)) ;
//printf(" deps idx::%i\n", genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[i].dps)[d].idx) ;
printf(" deps name::%s\n", string + genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[i].dps)[d].name) ;
//printf(" deps ndeps::%i\n", genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[i].dps)[d].ndeps) ;
// printf(" deps gaidx::%i\n---\n", genalloc_s(vertex_graph_t,&genalloc_s(vertex_graph_t,&g->vertex)[i].dps)[d].gaidx) ;
}
} */
return 1 ;
err:
genalloc_deepfree(stralist,&gatmp,stra_free) ;
stralloc_free(&res) ;
genalloc_free(vertex_graph_t,&gsv.dps) ;
genalloc_free(vertex_graph_t,&gdeps.dps) ;
return 0 ;
}
/** return idx of @name in @g
* @Return -1 if not found*/
int graph_search(graph_t *g, char const *name)
{
unsigned int i ;
char *string = g->string ;
for (i = 0 ; i < g->nvertex ; i++)
{
char *master = string + genalloc_s(vertex_graph_t,&g->vertex)[i].name ;
if (obstr_equal(name,master)) return i ;
}
return -1 ;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment