summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGalin Simeonov <gts@volconst.com>2021-10-01 14:05:00 +0300
committerGalin Simeonov <gts@volconst.com>2021-10-01 14:05:00 +0300
commit6a8bbbf82e21d90ef3609aae5046aef54024b5e0 (patch)
treeb161f1d3b556295807cb5e8388e72bc9441ce25b
parentf66d8e2562ec885c29a578956bf092a1e48cd9da (diff)
downloadvolgit-6a8bbbf82e21d90ef3609aae5046aef54024b5e0.tar.gz
Added tree like output
-rw-r--r--.exrc2
-rw-r--r--git_part.c218
-rw-r--r--git_part.h30
-rw-r--r--system_part.c44
-rw-r--r--system_part.h5
-rw-r--r--volgit.c2
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]
['>']="&gt;",
};
+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,"<pre>\n");
+ return ret;
+}
+void release_index_file(struct Index_File *index)
+{
+ fprintf(index->out,"</pre>\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;i<line->content_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;i<number_of_entries;++i)
{
current_entry=git_tree_entry_byindex(tree,i);
+
+ if(i<number_of_entries-1)
+ indentation_set_is_not_final(index_file,1);
+ else
+ indentation_set_is_not_final(index_file,0);
+
+
+ if(state.output_is_tree_like)
+ {
+ print_indentation_for_treelike_output(index_file);
+ if(i<number_of_entries-1)
+ fprintf(index_file->out,"├── ");
+ else
+ fprintf(index_file->out,"└── ");
+ }
print_entry(index_file,current_entry,dir_fd,repo);
- fprintf(index_file,"\n<br>\n");
+ if(i<number_of_entries-1)
+ fprintf(index_file->out,"\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,"<code><pre>\n");
- for(i=0;i<blob_size;++i)
- {
- if(special_chars[blob_data[i]])
- {
- fwrite(special_chars[blob_data[i]],1,strlen(special_chars[blob_data[i]]),blob_file);
- }else
- {
- fwrite(blob_data+i,1,1,blob_file);
- }
- }
- fprintf(blob_file,"</pre></code>\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,"<code><pre>\n");
+ for(i=0;i<blob_size;++i)
+ {
+ if(special_chars[blob_data[i]])
+ {
+ fwrite(special_chars[blob_data[i]],1,strlen(special_chars[blob_data[i]]),blob_file);
+ }else
+ {
+ fwrite(blob_data+i,1,1,blob_file);
+ }
+ }
+ fprintf(blob_file,"</pre></code>\n");
+
+ close_file(blob_file);
+}
+void print_indentation_for_treelike_output(struct Index_File *out)
+{
+ int i;
+ int j;
+ for(i=0;i<out->indentation;++i)
+ {
+ if(out->branches[i])
+ fprintf(out->out,"|");
+ else
+ fprintf(out->out," ");
+
+ for(j=0;j<out->offset[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 <git2.h>
#include <system_part.h>
+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="<!DOCTYPE html><html><head><title>GIT</title></head><body>";
const char *const default_footer="</body></html>";
-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,"<a href=\"%s.html\" class=\"blob_entry\">%s</a>\n",oid,filename);
+ fprintf(out,"<a href=\"%s.html\" class=\"blob_entry\">%s</a>",oid,filename);
}
void push_html_link_for_tree(FILE *out,const char *filename,const char *oid)
{
- fprintf(out,"<b><a href=\"%s/index.html\" class=\"tree_entry\">%s</a></b>\n",oid,filename);
+ fprintf(out,"<b><a href=\"%s/index.html\" class=\"tree_entry\">%s</a></b>",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");