F diff --git a/.exrc b/.exrc --- a/.exrc +++ b/.exrcset nomodelineset mouse=aset omnifunc=syntaxcomplete- set printoptions=paper:letter+ set printstate=paper:letterset rulerset showtabline=0set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.tocF diff --git a/git_part.c b/git_part.c --- a/git_part.c +++ b/git_part.c['>']=">",};+ 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){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);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);+ }#endifF diff --git a/git_part.h b/git_part.h --- a/git_part.h +++ b/git_part.h#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);+#endifF diff --git a/system_part.c b/system_part.c --- a/system_part.c +++ b/system_part.cconst 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,{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);}- 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{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);}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)}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);}#endifF diff --git a/system_part.h b/system_part.h --- a/system_part.h +++ b/system_part.h#define NO_TREE_CUTOFF -1+ #define MAX_CUTOFF 1024extern 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;int output_dir_fd;int tree_cutoff; /*-1 means no cutoff*/_Bool output_is_tree_like;- }options;+ }state;void die(const char *format, ...);F diff --git a/volgit.c b/volgit.c --- a/volgit.c +++ b/volgit.cparse_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");