From 6a8bbbf82e21d90ef3609aae5046aef54024b5e0 Mon Sep 17 00:00:00 2001 From: Galin Simeonov Date: Fri, 1 Oct 2021 14:05:00 +0300 Subject: Added tree like output --- .exrc | 2 +- git_part.c | 218 +++++++++++++++++++++++++++++++++++++++++++--------------- git_part.h | 30 +++++++- system_part.c | 44 ++++++------ system_part.h | 5 +- volgit.c | 2 +- 6 files changed, 219 insertions(+), 82 deletions(-) diff --git a/.exrc b/.exrc index 9cdfbae..64ab202 100644 --- a/.exrc +++ b/.exrc @@ -28,7 +28,7 @@ set makeprg=make\ -C/tmp/a set nomodeline set mouse=a set omnifunc=syntaxcomplete -set printoptions=paper:letter +set printstate=paper:letter set ruler set showtabline=0 set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.toc diff --git a/git_part.c b/git_part.c index 0355ec2..5f2fe7b 100644 --- a/git_part.c +++ b/git_part.c @@ -12,6 +12,21 @@ static const char *special_chars[256] ['>']=">", }; +struct Index_File *get_index_file(int dir_fd,const char *name) +{ + struct Index_File *ret; + ret=calloc(sizeof(struct Index_File),1); + ret->out=create_file(dir_fd,name); + + fprintf(ret->out,"
\n");
+	return ret;
+}
+void release_index_file(struct Index_File *index)
+{
+	fprintf(index->out,"
\n"); + close_file(index->out); + free(index); +} int print_diff_line(const git_diff_delta *delta,const git_diff_hunk *hunk,const git_diff_line *line,FILE *out) { @@ -25,9 +40,9 @@ int print_diff_line(const git_diff_delta *delta,const git_diff_hunk *hunk,const fprintf(out,"%c ",line->origin); for(i=0;icontent_len;++i) - if(special_chars[line->content[i]]) + if(special_chars[(unsigned char)line->content[i]]) { - fwrite(special_chars[line->content[i]],1,strlen(special_chars[line->content[i]]),out); + fwrite(special_chars[line->content[i]],1,strlen(special_chars[(unsigned char)line->content[i]]),out); }else { fwrite(line->content+i,1,1,out); @@ -162,95 +177,188 @@ void print_branches(git_repository *repo) git_branch_iterator_free(it); } -void print_files(int dir_fd,git_tree *tree,git_repository *repo) +void print_files(struct Index_File *index_file,int dir_fd,git_tree *tree,git_repository *repo) { size_t number_of_entries; size_t i; const git_tree_entry *current_entry; - FILE *index_file; number_of_entries=git_tree_entrycount(tree); - index_file=create_file(dir_fd,"index"); for(i=0;iout,"├── "); + else + fprintf(index_file->out,"└── "); + } print_entry(index_file,current_entry,dir_fd,repo); - fprintf(index_file,"\n
\n"); + if(iout,"\n"); } - close_file(index_file); } void print_files_top(int dir_fd,git_commit *top_commit,git_repository *repo) { + struct Index_File *index_file; git_tree *tree; git_commit_tree(&tree,top_commit); - print_files(dir_fd,tree,repo); + index_file=get_index_file(dir_fd,"index"); + + if(state.output_is_tree_like) + fprintf(index_file->out,"|\n"); + + print_files(index_file,dir_fd,tree,repo); + + + release_index_file(index_file); } -int print_entry(FILE *index_file,const git_tree_entry *entry,int base_dir_fd,git_repository *repo) +int print_entry(struct Index_File *index_file,const git_tree_entry *entry,int base_dir_fd,git_repository *repo) { git_object *obj; - const git_oid *obj_oid; const char *entry_name; - const char *entry_oid; git_tree_entry_to_object(&obj,repo,entry); - obj_oid=git_object_id(obj); - entry_name=git_tree_entry_name(entry); - entry_oid=git_oid_tostr_s(obj_oid); switch(git_object_type(obj)) { case GIT_OBJECT_TREE: - push_html_link_for_tree(index_file,entry_name,entry_oid); - { - int new_dir_fd; - git_tree *tree; - - tree=(git_tree*)obj; - - new_dir_fd=create_dir(base_dir_fd,entry_oid); - print_files(new_dir_fd,tree,repo); - } + print_tree_entry(index_file,entry_name,obj,base_dir_fd,repo); break; case GIT_OBJECT_BLOB: - push_html_link_for_blob(index_file,entry_name,entry_oid); - { - FILE *blob_file; - const unsigned char *blob_data; - size_t blob_size; - size_t i; - git_blob *blob; - - - blob=(git_blob*)obj; - - blob_file=create_file(base_dir_fd,entry_oid); - - blob_size=git_blob_rawsize(blob); - blob_data=git_blob_rawcontent(blob); - - fprintf(blob_file,"
\n");
-				for(i=0;i\n");
-
-				close_file(blob_file);
-			}
+			print_blob_entry(index_file,entry_name,obj,base_dir_fd,repo);
 			break;
 	}
 
 	git_object_free(obj);
 	return 0;
 }
+static inline void print_tree_entry(struct Index_File *index_file,const char *name,git_object *obj,int base_dir_fd,git_repository *repo)
+{
+	const git_oid *obj_oid;
+	const char *entry_oid;
+	git_tree *tree;
+	
+	obj_oid=git_object_id(obj);
+	entry_oid=git_oid_tostr_s(obj_oid);
+	tree=(git_tree*)obj;
+
+
+
+	if(state.output_is_tree_like)
+	{
+		if(index_file->indentation==state.tree_cutoff)
+		{
+			push_html_link_for_tree(index_file->out,name,entry_oid);
+			print_files_in_another_index(base_dir_fd,entry_oid,name,tree,repo);
+
+		}else
+		{
+			fprintf(index_file->out,"%s ─┐",name);	
+			increment_indentation(index_file,name);
+
+			fprintf(index_file->out,"\n");
+			print_files(index_file,base_dir_fd,tree,repo);
+			
+			decrement_indentation(index_file);	
+		}
+	}else
+	{
+		push_html_link_for_tree(index_file->out,name,entry_oid);
+		print_files_in_another_index(base_dir_fd,entry_oid,name,tree,repo);
+	}
+}
+static inline void print_blob_entry(struct Index_File *index_file,const char *name,git_object *obj,int base_dir_fd,git_repository *repo)
+{
+	const git_oid *obj_oid;
+	const char *entry_oid;
+
+	FILE *blob_file;
+	const unsigned char *blob_data;
+	size_t blob_size;
+	size_t i;
+	git_blob *blob;
+
+	obj_oid=git_object_id(obj);
+	entry_oid=git_oid_tostr_s(obj_oid);
+
+	push_html_link_for_blob(index_file->out,name,entry_oid);
+
+	blob=(git_blob*)obj;
+	blob_file=create_file(base_dir_fd,entry_oid);
+
+	blob_size=git_blob_rawsize(blob);
+	blob_data=git_blob_rawcontent(blob);
+
+	fprintf(blob_file,"
\n");
+	for(i=0;i\n");
+
+	close_file(blob_file);
+}
+void print_indentation_for_treelike_output(struct Index_File *out)
+{
+	int i;
+	int j;
+	for(i=0;iindentation;++i)
+	{
+		if(out->branches[i])
+			fprintf(out->out,"|");
+		else
+			fprintf(out->out," ");
+
+		for(j=0;joffset[i]+5;++j)
+			fprintf(out->out," ");
+	}
+}
+void increment_indentation(struct Index_File *index,const char *name)
+{
+	index->offset[index->indentation]=strnlen(name,1000);
+	++index->indentation;
+}
+void decrement_indentation(struct Index_File *index)
+{
+	--index->indentation;
+}
+void indentation_set_is_not_final(struct Index_File *index,_Bool is_final)
+{
+	index->branches[index->indentation]=is_final;
+}
+
+void print_files_in_another_index(int base_dir_fd,const char *entry_oid,const char *name,git_tree *tree,git_repository *repo)
+{
+	int new_dir_fd;
+	struct Index_File *new_index;
+
+	new_dir_fd=create_dir(base_dir_fd,entry_oid);
+	new_index=get_index_file(new_dir_fd,"index");
+	if(state.output_is_tree_like)
+		fprintf(new_index->out,"%s\n|\n",name);
+	print_files(new_index,new_dir_fd,tree,repo);
+	
+	release_index_file(new_index);
+	close(new_dir_fd);
+}
 #endif
diff --git a/git_part.h b/git_part.h
index c42230b..e16b02e 100644
--- a/git_part.h
+++ b/git_part.h
@@ -4,15 +4,41 @@
 #include 
 #include 
 
+struct Index_File
+{
+	FILE *out;
+	
+	/*these are used in treelike output*/
+	_Bool branches[MAX_CUTOFF];
+	/*
+	 offsets between different branches, if the dir name is long this prevents
+	 skewed branches below
+	 */
+	int offset[MAX_CUTOFF];
+	int indentation;
+};
+
+struct Index_File *get_index_file(int dir_fd,const char *name);
+void release_index_file(struct Index_File *index);
+
 int print_diff_line(const git_diff_delta *delta,const git_diff_hunk *hunk,const git_diff_line *line,FILE *out);
 void print_diff(FILE *out,git_tree *parent_tree,git_tree *current_tree,git_repository *repo);
 void print_headers_and_commit_message(FILE *where,git_commit *current_commit,const git_oid *current,_Bool has_diff);
 void print_commits(int dir_fd,const git_reference *branch, git_repository *repo);
 void print_commit(git_commit *current_commit,git_commit *parent_commit,FILE *log_file,int diff_directory_fd,git_repository *repo);
 void print_files_top(int dir_fd,git_commit *top_commit,git_repository *repo);
-void print_files(int dir_fd,git_tree *tree,git_repository *repo);
-int print_entry(FILE *index_file,const git_tree_entry *entry,int base_dir_fd,git_repository *repo);
+void print_files(struct Index_File *index_file,int dir_fd,git_tree *tree,git_repository *repo);
+int print_entry(struct Index_File *index_file,const git_tree_entry *entry,int base_dir_fd,git_repository *repo);
+static inline void print_tree_entry(struct Index_File *index_file,const char *name,git_object *obj,int base_dir_fd,git_repository *repo);
+static inline void print_blob_entry(struct Index_File *index_file,const char *name,git_object *obj,int base_dir_fd,git_repository *repo);
 
 void print_branches(git_repository *repo);
 
+void print_indentation_for_treelike_output(struct Index_File *out);
+
+void increment_indentation(struct Index_File *index,const char *name);
+void decrement_indentation(struct Index_File *index);
+void indentation_set_is_not_final(struct Index_File *index,_Bool is_final);
+void print_files_in_another_index(int base_dir_fd,const char *entry_oid,const char *name,git_tree *tree,git_repository *repo);
+
 #endif
diff --git a/system_part.c b/system_part.c
index 0c162b2..6d5f963 100644
--- a/system_part.c
+++ b/system_part.c
@@ -5,7 +5,7 @@
 const char *const default_header="GIT";
 const char *const default_footer="";
 
-struct Volgit_Options options
+struct Volgit_State state
 			=
 	{
 		.input_path=NULL,
@@ -52,36 +52,38 @@ void parse_options(int argc,char **argv)
 		{
 			i=get_next_option_or_die(i,argc,"expected a file name after --output flag\n");
 
-			options.output_path=argv[i];
-			options.output_dir_fd=open(options.output_path,O_RDONLY|O_DIRECTORY);
+			state.output_path=argv[i];
+			state.output_dir_fd=open(state.output_path,O_RDONLY|O_DIRECTORY);
 
-			if(options.output_dir_fd==-1)
+			if(state.output_dir_fd==-1)
 			{
-				mkdir(options.output_path,0775);
-				options.output_dir_fd=open(options.output_path,O_RDONLY|O_DIRECTORY);
-				if(options.output_dir_fd==-1)
+				mkdir(state.output_path,0775);
+				state.output_dir_fd=open(state.output_path,O_RDONLY|O_DIRECTORY);
+				if(state.output_dir_fd==-1)
 					die("Could not open output dir\n");
 			}
 		}else if_option("--input")
 		{
 			i=get_next_option_or_die(i,argc,"expected a file name after --input flag\n");
-			options.input_path=argv[i];
+			state.input_path=argv[i];
 		}else if_option("--header")
 		{
 			i=get_next_option_or_die(i,argc,"expected an argument after --header flag\n");	
-			options.header=read_file(argv[i]);	
+			state.header=read_file(argv[i]);	
 		}else if_option("--footer")
 		{
 			i=get_next_option_or_die(i,argc,"expected an argument after --footer flag\n");	
-			options.footer=read_file(argv[i]);
+			state.footer=read_file(argv[i]);
 		}else if_option("--tree")
 		{
-			options.output_is_tree_like=1;
+			state.output_is_tree_like=1;
 		}else if_option("--tree-cutoff")
 		{
 			i=get_next_option_or_die(i,argc,"expected an argument after --tree-cutoff flag\n");	
-			if(sscanf(argv[i],"%d",&options.tree_cutoff))
+			if(sscanf(argv[i],"%d",&state.tree_cutoff)!=1)
 				die("expected a number after the --tree-cutoff flag\n");
+			if(state.tree_cutoff>=MAX_CUTOFF-1)
+				die("cutoff number is too large. Max cutoff is %d\n",MAX_CUTOFF);
 		}else if_option("-h")
 		{
 			die(usage);
@@ -95,9 +97,9 @@ void parse_options(int argc,char **argv)
 
 	}
 
-	if(options.input_path==NULL)
+	if(state.input_path==NULL)
 		die("You need to specify an input path\n");
-	if(options.output_path==NULL)
+	if(state.output_path==NULL)
 		die("You need to specify an output path\n");
 
 #undef if_option
@@ -133,13 +135,13 @@ int create_branch_dir(const char *branch_name)
 {
 	int ret=0;
 
-	ret=openat(options.output_dir_fd,branch_name,O_DIRECTORY|O_RDONLY);	
+	ret=openat(state.output_dir_fd,branch_name,O_DIRECTORY|O_RDONLY);	
 	if(ret==-1)
 	{
-		if(mkdirat(options.output_dir_fd,branch_name,0775)==-1)
+		if(mkdirat(state.output_dir_fd,branch_name,0775)==-1)
 			die("Could not create branch directory for %s\n",branch_name);
 
-		ret=openat(options.output_dir_fd,branch_name,O_DIRECTORY|O_RDONLY);	
+		ret=openat(state.output_dir_fd,branch_name,O_DIRECTORY|O_RDONLY);	
 		if(ret==-1)
 			die("Could not open newly created directory for branch %s\n",branch_name);
 	}
@@ -170,12 +172,12 @@ FILE* create_file(int branch_dir,const char *filename)
 
 	ret=fdopen(fd,"w");
 
-	fprintf(ret,"%s",options.header);
+	fprintf(ret,"%s",state.header);
 	return ret;
 }
 void close_file(FILE *file)
 {
-	fprintf(file,"%s",options.footer);
+	fprintf(file,"%s",state.footer);
 	fclose(file);
 }
 int create_dir(int base_dir,const char *dir_name)
@@ -202,10 +204,10 @@ void die(const char *format, ...)
 }
 void push_html_link_for_blob(FILE *out,const char *filename,const char *oid)
 {
-	fprintf(out,"%s\n",oid,filename);	
+	fprintf(out,"%s",oid,filename);	
 }
 void push_html_link_for_tree(FILE *out,const char *filename,const char *oid)
 {
-	fprintf(out,"%s\n",oid,filename);	
+	fprintf(out,"%s",oid,filename);	
 }
 #endif
diff --git a/system_part.h b/system_part.h
index 3949d8b..9c4cc26 100644
--- a/system_part.h
+++ b/system_part.h
@@ -10,11 +10,12 @@
 
 
 #define NO_TREE_CUTOFF -1
+#define MAX_CUTOFF 1024
 
 extern const char *const default_header;
 extern const char *const default_footer;
 
-extern struct Volgit_Options
+extern struct Volgit_State
 {
 	const char *input_path;
 	const char *output_path;
@@ -26,7 +27,7 @@ extern struct Volgit_Options
 	int output_dir_fd;
 	int tree_cutoff; /*-1 means no cutoff*/
 	_Bool output_is_tree_like;
-}options;
+}state;
 
 void die(const char *format, ...);
 
diff --git a/volgit.c b/volgit.c
index cca9ae6..a92e388 100644
--- a/volgit.c
+++ b/volgit.c
@@ -12,7 +12,7 @@ int main(int argc,char **argv)
 
 	parse_options(argc,argv);	
 
-	git_repository_open(&repo,options.input_path);
+	git_repository_open(&repo,state.input_path);
 	if(repo==NULL)
 		die("Could not open input git repository\n");
 
-- 
cgit v1.2.3