diff options
-rw-r--r-- | .exrc | 2 | ||||
-rw-r--r-- | git_part.c | 218 | ||||
-rw-r--r-- | git_part.h | 30 | ||||
-rw-r--r-- | system_part.c | 44 | ||||
-rw-r--r-- | system_part.h | 5 | ||||
-rw-r--r-- | volgit.c | 2 |
6 files changed, 219 insertions, 82 deletions
@@ -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 @@ -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,"<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 @@ -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, ...); @@ -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"); |