F diff --git a/.exrc b/.exrc
--- a/.exrc
+++ b/.exrc
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
F 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);
+ }
#endif
F 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);
+
#endif
F diff --git a/system_part.c b/system_part.c
--- a/system_part.c
+++ b/system_part.c
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,
{
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);
}
#endif
F 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 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;
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.c
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");