#ifndef VOLGIT_GIT_PART_C #define VOLGIT_GIT_PART_C VOLGIT_GIT_PART_C #include 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) { size_t i; if(line->origin=='+') fprintf(out,"
"); else if(line->origin=='-') fprintf(out,"
"); else fprintf(out,"
"); fprintf(out,"%c ",line->origin); for(i=0;icontent_len;++i) if(special_chars[(unsigned char)line->content[i]]) { fwrite(special_chars[line->content[i]],1,strlen(special_chars[(unsigned char)line->content[i]]),out); }else { fwrite(line->content+i,1,1,out); } fprintf(out,"
"); return 0; } void print_diff(FILE *out,git_tree *parent_tree,git_tree *current_tree,git_repository *repo) { git_diff *diff_from_parent; size_t number_of_deltas=0; size_t i; fprintf(out,"
");
	git_diff_tree_to_tree(&diff_from_parent,repo,parent_tree,current_tree,NULL);

	git_diff_print(diff_from_parent,GIT_DIFF_FORMAT_PATCH_ID,(git_diff_line_cb)print_diff_line,out);

	if(diff_from_parent)
		git_diff_free(diff_from_parent);
	fprintf(out,"
"); } void print_headers_and_commit_message(FILE *where,git_commit *current_commit,const git_oid *current,_Bool has_diff) { const git_signature *who_commited; fprintf(where,"
COMMIT: %s",git_oid_tostr_s(current)); if(has_diff) fprintf(where," [DIFF]
\n",git_oid_tostr_s(current)); else fprintf(where,"
\n"); who_commited=git_commit_committer(current_commit); fprintf(where,"
AUTHOR: %s <%s>
\n",who_commited->name,who_commited->email); fprintf(where,"
DATE: %s
\n",ctime(&who_commited->when.time)); fprintf(where,"
\t%s
\n",git_commit_message(current_commit)); } void print_commits(int dir_fd,const git_reference *branch, git_repository *repo) { const git_oid *id; FILE *log_file; int diff_directory_fd; int files_directory_fd; git_revwalk *walker; git_oid current; git_commit *current_commit; git_commit *parent_commit=NULL; git_revwalk_new(&walker,repo); id=git_reference_target(branch); git_revwalk_push(walker,id); log_file=create_file(dir_fd,"log"); diff_directory_fd=create_dir(dir_fd,"diffs"); files_directory_fd=create_dir(dir_fd,"files"); if(git_revwalk_next(¤t,walker)) return; git_commit_lookup(¤t_commit,repo,¤t); print_files_top(files_directory_fd,current_commit,repo); while(!git_revwalk_next(¤t,walker)) { git_commit_lookup(&parent_commit,repo,¤t); print_commit(current_commit,parent_commit,log_file,diff_directory_fd,repo); git_commit_free(current_commit); current_commit=parent_commit; } if(parent_commit!=NULL) print_commit(current_commit,NULL,log_file,diff_directory_fd,repo); git_revwalk_free(walker); close_file(log_file); } void print_commit(git_commit *current_commit,git_commit *parent_commit,FILE *log_file,int diff_directory_fd,git_repository *repo) { git_tree *current_tree; git_tree *parent_tree; FILE *diff_file; git_commit_tree(¤t_tree,current_commit); if(parent_commit==NULL) parent_tree=NULL; else git_commit_tree(&parent_tree,parent_commit); diff_file=create_file(diff_directory_fd,git_oid_tostr_s(git_commit_id(current_commit))); print_diff(diff_file,parent_tree,current_tree,repo); git_tree_free(parent_tree); print_headers_and_commit_message(log_file,current_commit,git_commit_id(current_commit),1); close_file(diff_file); } void print_branches(git_repository *repo) { const char *branch_name; int branch_dir_fd; git_branch_iterator *it; git_reference *ref; git_branch_t branch_type=GIT_BRANCH_LOCAL; git_branch_iterator_new(&it,repo,branch_type); while(git_branch_next(&ref,&branch_type,it)==0) { git_branch_name(&branch_name,ref); if(branch_name) { branch_dir_fd=create_branch_dir(branch_name); print_commits(branch_dir_fd,ref,repo); close(branch_dir_fd); }else { printf("NULL\n"); } } git_branch_iterator_free(it); } 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; number_of_entries=git_tree_entrycount(tree); for(i=0;iout,"├── "); else fprintf(index_file->out,"└── "); } print_entry(index_file,current_entry,dir_fd,repo); if(iout,"\n"); } } 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); 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(struct Index_File *index_file,const git_tree_entry *entry,int base_dir_fd,git_repository *repo) { git_object *obj; const char *entry_name; git_tree_entry_to_object(&obj,repo,entry); entry_name=git_tree_entry_name(entry); switch(git_object_type(obj)) { case GIT_OBJECT_TREE: print_tree_entry(index_file,entry_name,obj,base_dir_fd,repo); break; case GIT_OBJECT_BLOB: 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]+2;++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