Skip to content
Snippets Groups Projects
ss_info_utils.c 6.72 KiB
/* 
 * ss_info_utils.c
 * 
 * Copyright (c) 2018-2020 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 <66/info.h>

#include <unistd.h>
#include <sys/ioctl.h>
#include <wchar.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> //ssize_t

#include <oblibs/sastr.h>
#include <oblibs/log.h>

#include <skalibs/buffer.h>
#include <skalibs/lolstdio.h>

#include <s6/s6-supervise.h>

#include <66/resolve.h>

unsigned int MAXDEPTH = 1 ;

ss_resolve_graph_style graph_utf8 = {
	UTF_VR UTF_H,
	UTF_UR UTF_H,
	UTF_V " ",
	2
} ;

ss_resolve_graph_style graph_default = {
	"|-",
	"`-",
	"|",
	2
} ;

int info_getcols_fd(int fd)
{
	int width = -1;

	if(!isatty(fd))	return 0;

#if defined(TIOCGSIZE)
	struct ttysize win;
	if(ioctl(fd, TIOCGSIZE, &win) == 0)
		width = win.ts_cols;
#elif defined(TIOCGWINSZ)
	struct winsize win;
	if(ioctl(fd, TIOCGWINSZ, &win) == 0)
		width = win.ws_col;
#endif
	
	// return abitrary value
	if(width <= 0) return 100 ;
	
	return width;
}

void info_field_align (char buf[][INFO_FIELD_MAXLEN],char fields[][INFO_FIELD_MAXLEN],wchar_t const field_suffix[],size_t buflen)
{
	unsigned int i ;
	
	size_t maxlen = 0 ;
	
	int maxcol = 0 ;
	
	static wchar_t wbuf[][INFO_FIELD_MAXLEN+nb_el(field_suffix)] = {{ 0 }} ;
	
	size_t wlen[buflen] ;
	
	int wcol[buflen] ;

	for(i = 0; i < buflen; i++)
	{
		wlen[i] = mbstowcs(wbuf[i], buf[i], strlen(buf[i]) + 1) ;
		wcol[i] = wcswidth(wbuf[i], wlen[i]) ;
		if(wcol[i] > maxcol) {
			maxcol = wcol[i] ;
		}
		if(wlen[i] > maxlen) {
			maxlen = wlen[i] ;
		}
	}

	for(i = 0; i < buflen; i++)
	{
		size_t padlen = maxcol - wcol[i] ;
		wmemset(wbuf[i] + wlen[i], L' ', padlen) ;
		wmemcpy(wbuf[i] + wlen[i] + padlen, field_suffix, nb_el(field_suffix)) ;
		wcstombs(fields[i], wbuf[i], sizeof(wbuf[i])) ;
	}
}

size_t info_length_from_wchar(char const *str)
{
	ssize_t len ;
	wchar_t *wcstr ;
	if(!str || !str[0]) return 0 ;
	
	len = strlen(str) + 1 ;
	wcstr = calloc(len, sizeof(wchar_t)) ;
	len = mbstowcs(wcstr, str, len) ;
	len = wcswidth(wcstr, len) ;
	free(wcstr) ;

	return len == -1 ? 0 : (size_t)len  ;
}

size_t info_display_field_name(char const *field)
{
	size_t len = 0 ;
	if(field)
	{
		len = info_length_from_wchar(field) + 1 ;
		if (!bprintf(buffer_1,"%s%s%s ", log_color->info, field, log_color->off)) log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
	}
	return len ;
}

void info_display_list(char const *field, stralloc *list)
{
	size_t a = 0 , b, cols, padding = 0, slen = 0 ;
	
	unsigned short maxcols = info_getcols_fd(1) ;
	
	padding = info_length_from_wchar(field) + 1 ;
	
	cols = padding ;
	
	for (; a < list->len ; a += strlen(list->s + a) + 1)
	{
		char const *str = list->s + a ;
		slen = info_length_from_wchar(str) ;
		if((maxcols > padding) && (cols + slen + 2 >= maxcols))
		{
			cols = padding ;
			if (buffer_puts(buffer_1,"\n") == -1) goto err ;
			for(b = 1 ; b <= padding ; b++)
				if (buffer_puts(buffer_1," ") == -1) goto err ;
		} 
		else if (cols != padding)
		{
			if (buffer_puts(buffer_1," ") == -1) goto err ;
			cols += 2 ;
		}
		if (!bprintf(buffer_1,"%s",str)) goto err ;
		cols += slen ;
	}
	if (buffer_puts(buffer_1,"\n") == -1) goto err ;
	
	return ;
	err:
		log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
}

void info_display_nline(char const *field,char const *str)
{
	size_t pos = 0, padding = info_length_from_wchar(field) + 1 ;
	stralloc tmp = STRALLOC_ZERO ;
	stralloc cp = STRALLOC_ZERO ;
	if (!stralloc_cats(&tmp,str) ||
	!stralloc_0(&tmp)) log_die_nomem("stralloc") ;
	if (!sastr_split_string_in_nline(&tmp)) log_dieu(LOG_EXIT_SYS,"split string in nline") ;
	for (;pos < tmp.len ; pos += strlen(tmp.s + pos) + 1)
	{
		cp.len = 0 ;
		if (!stralloc_cats(&cp,tmp.s + pos) ||
		!stralloc_0(&cp)) log_die_nomem("stralloc") ;
		if (field) 
		{
			if (pos)
			{
				if (!bprintf(buffer_1,"%*s",padding,""))
					log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
			}
		}
		info_display_list(field,&cp) ;
	}
	stralloc_free(&tmp) ;
	stralloc_free(&cp) ;
}

void info_graph_display(ss_resolve_t *res, depth_t *depth, int last, int padding, ss_resolve_graph_style *style)
{
	s6_svstatus_t status = S6_SVSTATUS_ZERO ;
	char *name = res->sa.s + res->name ;
	if (res->type == CLASSIC || res->type == LONGRUN)
	{
		s6_svstatus_read(res->sa.s + res->runat ,&status) ;
	}
	else status.pid = 0 ;	
	
	const char *tip = "" ;
	int level = 1 ;
	
	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) + (level == 1 ? padding : 0), "", style->indent, style->limb)) return ;
		level = depth->level + 1 ;
		depth = depth->next ;
	} 
	
	if (!bprintf(buffer_1,"%*s%*s%s(%s%i%s,%s%s%s,%s) %s",level == 1 ? padding : 0,"", style->indent * (depth->level - level), "", tip, status.pid ? log_color->valid : log_color->off,status.pid ? status.pid : 0,log_color->off, res->disen ? log_color->off : log_color->error, res->disen ? "Enabled" : "Disabled",log_color->off,get_keybyid(res->type), name)) return ;

	if (buffer_putsflush(buffer_1,"\n") < 0) return ; 
}

int info_walk(ss_resolve_t *res,char const *src,int reverse, depth_t *depth, int padding, ss_resolve_graph_style *style)
{
	size_t pos = 0, idx = 0 ;
	stralloc sadeps = STRALLOC_ZERO ;
	ss_resolve_t dres = RESOLVE_ZERO ;
	
	if((!res->ndeps) || (depth->level > MAXDEPTH))
		goto freed ;
	
	if (!sastr_clean_string(&sadeps,res->sa.s + res->deps)) goto err ;
	if (reverse) sastr_reverse(&sadeps) ;

	for(; pos < sadeps.len ; pos += strlen(sadeps.s + pos) + 1,idx++ )
	{	
		int last =  idx + 1 < res->ndeps  ? 0 : 1 ;		
		char *name = sadeps.s + pos ;
		
		if (!ss_resolve_check(src,name)) goto err ;	
		if (!ss_resolve_read(&dres,src,name)) goto err ;
		
		info_graph_display(&dres, depth, last,padding,style) ;
						
		if (dres.ndeps)
		{
			depth_t d =
			{
				depth,
				NULL,
				depth->level + 1 	
			} ;
			depth->next = &d;
			
			if(last)
			{
				if(depth->prev)
				{
					depth->prev->next = &d;
					d.prev = depth->prev;
					depth = &d;
										
				}
				else 
					d.prev = NULL;
			}
			if (!info_walk(&dres, src, reverse, &d, padding, style)) goto err;
			depth->next = NULL;
		}
	}
	freed:
	ss_resolve_free(&dres) ;
	stralloc_free(&sadeps) ;
	return 1 ;
	err: 
		ss_resolve_free(&dres) ;
		stralloc_free(&sadeps) ;
		return 0 ;
}

int info_graph_init (ss_resolve_t *res,char const *src,unsigned int reverse, int padding, ss_resolve_graph_style *style)
{
	depth_t d = {
		NULL,
		NULL,
		1
	} ;	

	if(!info_walk(res,src,reverse,&d,padding,style)) return 0 ;
	
	return 1 ;
}