@ -1,6 +1,6 @@
/* ui-shared.c: common web output functions
*
* Copyright ( C ) 2006 - 201 7 cgit Development Team < cgit @ lists . zx2c4 . com >
* Copyright ( C ) 2006 - 201 4 cgit Development Team < cgit @ lists . zx2c4 . com >
*
* Licensed under GNU General Public License v2
* ( see COPYING for full license text )
@ -10,10 +10,10 @@
# include "ui-shared.h"
# include "cmd.h"
# include "html.h"
# include "version.h"
static const char cgit_doctype [ ] =
" <!DOCTYPE html> \n " ;
" <!DOCTYPE html PUBLIC \" -//W3C//DTD XHTML 1.0 Transitional//EN \" \n "
" \" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \" > \n " ;
static char * http_date ( time_t t )
{
@ -22,11 +22,10 @@ static char *http_date(time_t t)
static char month [ ] [ 4 ] =
{ " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " ,
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " } ;
struct tm tm ;
gmtime_r ( & t , & tm ) ;
return fmt ( " %s, %02d %s %04d %02d:%02d:%02d GMT " , day [ tm . tm_wday ] ,
tm . tm_mday , month [ tm . tm_mon ] , 1900 + tm . tm_year ,
tm . tm_hour , tm . tm_min , tm . tm_sec ) ;
struct tm * tm = gmtime ( & t ) ;
return fmt ( " %s, %02d %s %04d %02d:%02d:%02d GMT " , day [ tm - > tm_wday ] ,
tm - > tm_mday , month [ tm - > tm_mon ] , 1900 + tm - > tm_year ,
tm - > tm_hour , tm - > tm_min , tm - > tm_sec ) ;
}
void cgit_print_error ( const char * fmt , . . . )
@ -55,62 +54,28 @@ const char *cgit_httpscheme(void)
return " http:// " ;
}
char * cgit_hosturl ( void )
const char * cgit_hosturl ( void )
{
if ( ctx . env . http_host )
return xstrdup ( ctx . env . http_host ) ;
return ctx . env . http_host ;
if ( ! ctx . env . server_name )
return NULL ;
if ( ! ctx . env . server_port | | atoi ( ctx . env . server_port ) = = 80 )
return xstrdup ( ctx . env . server_name ) ;
return ctx . env . server_name ;
return fmtalloc ( " %s:%s " , ctx . env . server_name , ctx . env . server_port ) ;
}
char * cgit_currenturl ( void )
const char * cgit_currenturl ( void )
{
const char * root = cgit_rooturl ( ) ;
if ( ! ctx . qry . url )
return xstrdup ( root ) ;
if ( root [ 0 ] & & root [ strlen ( root ) - 1 ] = = ' / ' )
return cgit_rooturl ( ) ;
const char * root = cgit_rooturl ( ) ;
size_t len = strlen ( root ) ;
if ( len & & root [ len - 1 ] = = ' / ' )
return fmtalloc ( " %s%s " , root , ctx . qry . url ) ;
return fmtalloc ( " %s/%s " , root , ctx . qry . url ) ;
}
char * cgit_currentfullurl ( void )
{
const char * root = cgit_rooturl ( ) ;
const char * orig_query = ctx . env . query_string ? ctx . env . query_string : " " ;
size_t len = strlen ( orig_query ) ;
char * query = xmalloc ( len + 2 ) , * start_url , * ret ;
/* Remove all url=... parts from query string */
memcpy ( query + 1 , orig_query , len + 1 ) ;
query [ 0 ] = ' ? ' ;
start_url = query ;
while ( ( start_url = strstr ( start_url , " url= " ) ) ! = NULL ) {
if ( start_url [ - 1 ] = = ' ? ' | | start_url [ - 1 ] = = ' & ' ) {
const char * end_url = strchr ( start_url , ' & ' ) ;
if ( end_url )
memmove ( start_url , end_url + 1 , strlen ( end_url ) ) ;
else
start_url [ 0 ] = ' \0 ' ;
} else
+ + start_url ;
}
if ( ! query [ 1 ] )
query [ 0 ] = ' \0 ' ;
if ( ! ctx . qry . url )
ret = fmtalloc ( " %s%s " , root , query ) ;
else if ( root [ 0 ] & & root [ strlen ( root ) - 1 ] = = ' / ' )
ret = fmtalloc ( " %s%s%s " , root , ctx . qry . url , query ) ;
else
ret = fmtalloc ( " %s/%s%s " , root , ctx . qry . url , query ) ;
free ( query ) ;
return ret ;
}
const char * cgit_rooturl ( void )
{
if ( ctx . cfg . virtual_root )
@ -167,49 +132,33 @@ const char *cgit_repobasename(const char *reponame)
static char rvbuf [ 1024 ] ;
int p ;
const char * rv ;
size_t len ;
len = strlcpy ( rvbuf , reponame , sizeof ( rvbuf ) ) ;
if ( len > = sizeof ( rvbuf ) )
strncpy ( rvbuf , reponame , sizeof ( rvbuf ) ) ;
if ( rvbuf [ sizeof ( rvbuf ) - 1 ] )
die ( " cgit_repobasename: truncated repository name '%s' " , reponame ) ;
p = len - 1 ;
p = strlen ( rvbuf ) - 1 ;
/* strip trailing slashes */
while ( p & & rvbuf [ p ] = = ' / ' )
rvbuf [ p - - ] = ' \0 ' ;
while ( p & & rvbuf [ p ] = = ' / ' ) rvbuf [ p - - ] = 0 ;
/* strip trailing .git */
if ( p > = 3 & & starts_with ( & rvbuf [ p - 3 ] , " .git " ) ) {
p - = 3 ;
rvbuf [ p - - ] = ' \0 ' ;
p - = 3 ; rvbuf [ p - - ] = 0 ;
}
/* strip more trailing slashes if any */
while ( p & & rvbuf [ p ] = = ' / ' )
rvbuf [ p - - ] = ' \0 ' ;
while ( p & & rvbuf [ p ] = = ' / ' ) rvbuf [ p - - ] = 0 ;
/* find last slash in the remaining string */
rv = strrchr ( rvbuf , ' / ' ) ;
rv = strrchr ( rvbuf , ' / ' ) ;
if ( rv )
return + + rv ;
return rvbuf ;
}
const char * cgit_snapshot_prefix ( const struct cgit_repo * repo )
{
if ( repo - > snapshot_prefix )
return repo - > snapshot_prefix ;
return cgit_repobasename ( repo - > url ) ;
}
static void site_url ( const char * page , const char * search , const char * sort , int ofs , int always_root )
{
char * delim = " ? " ;
if ( always_root | | page )
html_attr ( cgit_rooturl ( ) ) ;
else {
char * currenturl = cgit_currenturl ( ) ;
html_attr ( currenturl ) ;
free ( currenturl ) ;
}
else
html_attr ( cgit_currenturl ( ) ) ;
if ( page ) {
htmlf ( " ?p=%s " , page ) ;
@ -302,7 +251,7 @@ static char *repolink(const char *title, const char *class, const char *page,
}
delim = " & " ;
}
if ( head & & ctx . repo - > defbranch & & strcmp ( head , ctx . repo - > defbranch ) ) {
if ( head & & strcmp ( head , ctx . repo - > defbranch ) ) {
html ( delim ) ;
html ( " h= " ) ;
html_url_arg ( head ) ;
@ -352,16 +301,9 @@ void cgit_plain_link(const char *name, const char *title, const char *class,
reporevlink ( " plain " , name , title , class , head , rev , path ) ;
}
void cgit_blame_link ( const char * name , const char * title , const char * class ,
const char * head , const char * rev , const char * path )
{
reporevlink ( " blame " , name , title , class , head , rev , path ) ;
}
void cgit_log_link ( const char * name , const char * title , const char * class ,
const char * head , const char * rev , const char * path ,
int ofs , const char * grep , const char * pattern , int showmsg ,
int follow )
int ofs , const char * grep , const char * pattern , int showmsg )
{
char * delim ;
@ -390,20 +332,22 @@ void cgit_log_link(const char *name, const char *title, const char *class,
if ( showmsg ) {
html ( delim ) ;
html ( " showmsg=1 " ) ;
delim = " & " ;
}
if ( follow ) {
html ( delim ) ;
html ( " follow=1 " ) ;
}
html ( " '> " ) ;
html_txt ( name ) ;
html ( " </a> " ) ;
}
void cgit_commit_link ( const char * name , const char * title , const char * class ,
void cgit_commit_link ( char * name , const char * title , const char * class ,
const char * head , const char * rev , const char * path )
{
if ( strlen ( name ) > ctx . cfg . max_msg_len & & ctx . cfg . max_msg_len > = 15 ) {
name [ ctx . cfg . max_msg_len ] = ' \0 ' ;
name [ ctx . cfg . max_msg_len - 1 ] = ' . ' ;
name [ ctx . cfg . max_msg_len - 2 ] = ' . ' ;
name [ ctx . cfg . max_msg_len - 3 ] = ' . ' ;
}
char * delim ;
delim = repolink ( title , class , " commit " , head , path ) ;
@ -429,18 +373,10 @@ void cgit_commit_link(const char *name, const char *title, const char *class,
html ( " ignorews=1 " ) ;
delim = " & " ;
}
if ( ctx . qry . follow ) {
html ( delim ) ;
html ( " follow=1 " ) ;
}
html ( " '> " ) ;
if ( name [ 0 ] ! = ' \0 ' ) {
if ( strlen ( name ) > ctx . cfg . max_msg_len & & ctx . cfg . max_msg_len > = 15 ) {
html_ntxt ( name , ctx . cfg . max_msg_len - 3 ) ;
html ( " ... " ) ;
} else
html_txt ( name ) ;
} else
if ( name [ 0 ] ! = ' \0 ' )
html_txt ( name ) ;
else
html_txt ( " (no commit message) " ) ;
html ( " </a> " ) ;
}
@ -493,10 +429,6 @@ void cgit_diff_link(const char *name, const char *title, const char *class,
html ( " ignorews=1 " ) ;
delim = " & " ;
}
if ( ctx . qry . follow ) {
html ( delim ) ;
html ( " follow=1 " ) ;
}
html ( " '> " ) ;
html_txt ( name ) ;
html ( " </a> " ) ;
@ -522,45 +454,41 @@ static void cgit_self_link(char *name, const char *title, const char *class)
else if ( ! strcmp ( ctx . qry . page , " summary " ) )
cgit_summary_link ( name , title , class , ctx . qry . head ) ;
else if ( ! strcmp ( ctx . qry . page , " tag " ) )
cgit_tag_link ( name , title , class , ctx . qry . has_ oid ?
ctx . qry . oid : ctx . qry . head ) ;
cgit_tag_link ( name , title , class , ctx . qry . has_ sha1 ?
ctx . qry . sha1 : ctx . qry . head ) ;
else if ( ! strcmp ( ctx . qry . page , " tree " ) )
cgit_tree_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_ oid ? ctx . qry . oid : NULL ,
ctx . qry . has_ sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " plain " ) )
cgit_plain_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_oid ? ctx . qry . oid : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " blame " ) )
cgit_blame_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_oid ? ctx . qry . oid : NULL ,
ctx . qry . has_sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " log " ) )
cgit_log_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_ oid ? ctx . qry . oid : NULL ,
ctx . qry . has_sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path , ctx . qry . ofs ,
ctx . qry . grep , ctx . qry . search ,
ctx . qry . showmsg , ctx . qry . follow );
ctx . qry . showmsg );
else if ( ! strcmp ( ctx . qry . page , " commit " ) )
cgit_commit_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_ oid ? ctx . qry . oid : NULL ,
ctx . qry . has_ sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " patch " ) )
cgit_patch_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_ oid ? ctx . qry . oid : NULL ,
ctx . qry . has_ sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " refs " ) )
cgit_refs_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_ oid ? ctx . qry . oid : NULL ,
ctx . qry . has_ sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " snapshot " ) )
cgit_snapshot_link ( name , title , class , ctx . qry . head ,
ctx . qry . has_ oid ? ctx . qry . oid : NULL ,
ctx . qry . has_ sha1 ? ctx . qry . sha1 : NULL ,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " diff " ) )
cgit_diff_link ( name , title , class , ctx . qry . head ,
ctx . qry . oid, ctx . qry . oid 2,
ctx . qry . sha1, ctx . qry . sha 2,
ctx . qry . path ) ;
else if ( ! strcmp ( ctx . qry . page , " stats " ) )
cgit_stats_link ( name , title , class , ctx . qry . head ,
@ -580,7 +508,7 @@ void cgit_object_link(struct object *obj)
{
char * page , * shortrev , * fullrev , * name ;
fullrev = oid_to_hex( & obj - > oid ) ;
fullrev = sha1_to_hex( obj - > sha1 ) ;
shortrev = xstrdup ( fullrev ) ;
shortrev [ 10 ] = ' \0 ' ;
if ( obj - > type = = OBJ_COMMIT ) {
@ -593,7 +521,7 @@ void cgit_object_link(struct object *obj)
page = " tag " ;
else
page = " blob " ;
name = fmt ( " %s %s... " , type_ name( obj - > type ) , shortrev ) ;
name = fmt ( " %s %s... " , type name( obj - > type ) , shortrev ) ;
reporevlink ( page , name , NULL , NULL , ctx . qry . head , fullrev , NULL ) ;
}
@ -662,23 +590,39 @@ void cgit_submodule_link(const char *class, char *path, const char *rev)
path [ len - 1 ] = tail ;
}
const struct date_mode * cgit_date_mode ( enum date_mode_type typ e)
void cgit_print_date ( time_t secs , const char * format , int local_tim e)
{
static struct date_mode mode ;
mode . type = type ;
mode . local = ctx . cfg . local_time ;
return & mode ;
char buf [ 64 ] ;
struct tm * time ;
if ( ! secs )
return ;
if ( local_time )
time = localtime ( & secs ) ;
else
time = gmtime ( & secs ) ;
strftime ( buf , sizeof ( buf ) - 1 , format , time ) ;
html_txt ( buf ) ;
}
static void print_rel_date ( time_t t , int tz , double value ,
static void print_rel_date ( time_t t , double value ,
const char * class , const char * suffix )
{
htmlf ( " <span class='%s' data-ut='% " PRIu64 " ' title=' " , class , ( uint64_t ) t ) ;
html_attr ( show_date ( t , tz , cgit_date_mode ( DATE_ISO8601 ) ) ) ;
char buf [ 64 ] ;
struct tm * time ;
if ( ctx . cfg . local_time )
time = localtime ( & t ) ;
else
time = gmtime ( & t ) ;
strftime ( buf , sizeof ( buf ) - 1 , FMT_LONGDATE , time ) ;
htmlf ( " <span class='%s' title=' " , class ) ;
html_attr ( buf ) ;
htmlf ( " '>%.0f %s</span> " , value , suffix ) ;
}
void cgit_print_age ( time_t t , int tz , time_t max_relative )
void cgit_print_age ( time_t t , time_t max_relative , const char * format )
{
time_t now , secs ;
@ -690,35 +634,31 @@ void cgit_print_age(time_t t, int tz, time_t max_relative)
secs = 0 ;
if ( secs > max_relative & & max_relative > = 0 ) {
html ( " <span title=' " ) ;
html_attr ( show_date ( t , tz , cgit_date_mode ( DATE_ISO8601 ) ) ) ;
html ( " '> " ) ;
html_txt ( show_date ( t , tz , cgit_date_mode ( DATE_SHORT ) ) ) ;
html ( " </span> " ) ;
cgit_print_date ( t , format , ctx . cfg . local_time ) ;
return ;
}
if ( secs < TM_HOUR * 2 ) {
print_rel_date ( t , tz, secs * 1.0 / TM_MIN , " age-mins " , " min. " ) ;
print_rel_date ( t , secs * 1.0 / TM_MIN , " age-mins " , " min. " ) ;
return ;
}
if ( secs < TM_DAY * 2 ) {
print_rel_date ( t , tz, secs * 1.0 / TM_HOUR , " age-hours " , " hours " ) ;
print_rel_date ( t , secs * 1.0 / TM_HOUR , " age-hours " , " hours " ) ;
return ;
}
if ( secs < TM_WEEK * 2 ) {
print_rel_date ( t , tz, secs * 1.0 / TM_DAY , " age-days " , " days " ) ;
print_rel_date ( t , secs * 1.0 / TM_DAY , " age-days " , " days " ) ;
return ;
}
if ( secs < TM_MONTH * 2 ) {
print_rel_date ( t , tz, secs * 1.0 / TM_WEEK , " age-weeks " , " weeks " ) ;
print_rel_date ( t , secs * 1.0 / TM_WEEK , " age-weeks " , " weeks " ) ;
return ;
}
if ( secs < TM_YEAR * 2 ) {
print_rel_date ( t , tz, secs * 1.0 / TM_MONTH , " age-months " , " months " ) ;
print_rel_date ( t , secs * 1.0 / TM_MONTH , " age-months " , " months " ) ;
return ;
}
print_rel_date ( t , tz, secs * 1.0 / TM_YEAR , " age-years " , " years " ) ;
print_rel_date ( t , secs * 1.0 / TM_YEAR , " age-years " , " years " ) ;
}
void cgit_print_http_headers ( void )
@ -735,11 +675,9 @@ void cgit_print_http_headers(void)
htmlf ( " Content-Type: %s \n " , ctx . page . mimetype ) ;
if ( ctx . page . size )
htmlf ( " Content-Length: %zd \n " , ctx . page . size ) ;
if ( ctx . page . filename ) {
html ( " Content-Disposition: inline; filename= \" " ) ;
html_header_arg_in_quotes ( ctx . page . filename ) ;
html ( " \" \n " ) ;
}
if ( ctx . page . filename )
htmlf ( " Content-Disposition: inline; filename= \" %s \" \n " ,
ctx . page . filename ) ;
if ( ! ctx . env . authenticated )
html ( " Cache-Control: no-cache, no-store \n " ) ;
htmlf ( " Last-Modified: %s \n " , http_date ( ctx . page . modified ) ) ;
@ -751,14 +689,6 @@ void cgit_print_http_headers(void)
exit ( 0 ) ;
}
void cgit_redirect ( const char * url , bool permanent )
{
htmlf ( " Status: %d %s \n " , permanent ? 301 : 302 , permanent ? " Moved " : " Found " ) ;
html ( " Location: " ) ;
html_url_path ( url ) ;
html ( " \n \n " ) ;
}
static void print_rel_vcs_link ( const char * url )
{
html ( " <link rel='vcs-git' href=' " ) ;
@ -768,50 +698,17 @@ static void print_rel_vcs_link(const char *url)
html ( " Git repository'/> \n " ) ;
}
static int emit_css_link ( struct string_list_item * s , void * arg )
{
/* Do not emit anything if css= is specified. */
if ( s & & * s - > string = = ' \0 ' )
return 0 ;
html ( " <link rel='stylesheet' type='text/css' href=' " ) ;
if ( s )
html_attr ( s - > string ) ;
else
html_attr ( ( const char * ) arg ) ;
html ( " '/> \n " ) ;
return 0 ;
}
static int emit_js_link ( struct string_list_item * s , void * arg )
{
/* Do not emit anything if js= is specified. */
if ( s & & * s - > string = = ' \0 ' )
return 0 ;
html ( " <script type='text/javascript' src=' " ) ;
if ( s )
html_attr ( s - > string ) ;
else
html_attr ( ( const char * ) arg ) ;
html ( " '></script> \n " ) ;
return 0 ;
}
void cgit_print_docstart ( void )
{
char * host = cgit_hosturl ( ) ;
if ( ctx . cfg . embedded ) {
if ( ctx . cfg . header )
html_include ( ctx . cfg . header ) ;
return ;
}
const char * host = cgit_hosturl ( ) ;
html ( cgit_doctype ) ;
html ( " <html lang='en'>\n " ) ;
html ( " <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'> \n " ) ;
html ( " <head> \n " ) ;
html ( " <title> " ) ;
html_txt ( ctx . page . title ) ;
@ -819,48 +716,34 @@ void cgit_print_docstart(void)
htmlf ( " <meta name='generator' content='cgit %s'/> \n " , cgit_version ) ;
if ( ctx . cfg . robots & & * ctx . cfg . robots )
htmlf ( " <meta name='robots' content='%s'/> \n " , ctx . cfg . robots ) ;
if ( ctx . cfg . css . items )
for_each_string_list ( & ctx . cfg . css , emit_css_link , NULL ) ;
else
emit_css_link ( NULL , " /cgit.css " ) ;
if ( ctx . cfg . js . items )
for_each_string_list ( & ctx . cfg . js , emit_js_link , NULL ) ;
else
emit_js_link ( NULL , " /cgit.js " ) ;
html ( " <link rel='stylesheet' type='text/css' href=' " ) ;
html_attr ( ctx . cfg . css ) ;
html ( " '/> \n " ) ;
if ( ctx . cfg . favicon ) {
html ( " <link rel='shortcut icon' href=' " ) ;
html_attr ( ctx . cfg . favicon ) ;
html ( " '/> \n " ) ;
}
if ( host & & ctx . repo & & ctx . qry . head ) {
char * fileurl ;
struct strbuf sb = STRBUF_INIT ;
strbuf_addf ( & sb , " h=%s " , ctx . qry . head ) ;
html ( " <link rel='alternate' title='Atom feed' href=' " ) ;
html ( cgit_httpscheme ( ) ) ;
html_attr ( host ) ;
fileurl = cgit_fileurl ( ctx . repo - > url , " atom " , ctx . qry . vpath ,
sb . buf ) ;
html_attr ( fileurl ) ;
html_attr ( cgit_hosturl ( ) ) ;
html_attr ( cgit_fileurl ( ctx . repo - > url , " atom " , ctx . qry . vpath ,
sb . buf ) ) ;
html ( " ' type='application/atom+xml'/> \n " ) ;
strbuf_release ( & sb ) ;
free ( fileurl ) ;
}
if ( ctx . repo )
cgit_add_clone_urls ( print_rel_vcs_link ) ;
if ( ctx . cfg . head_include )
html_include ( ctx . cfg . head_include ) ;
if ( ctx . repo & & ctx . repo - > extra_head_content )
html ( ctx . repo - > extra_head_content ) ;
html ( " </head> \n " ) ;
html ( " <body> \n " ) ;
if ( ctx . cfg . header )
html_include ( ctx . cfg . header ) ;
free ( host ) ;
}
void cgit_print_docend ( void )
@ -875,40 +758,15 @@ void cgit_print_docend(void)
if ( ctx . cfg . footer )
html_include ( ctx . cfg . footer ) ;
else {
htmlf ( " <div class='footer'>generated by <a href='http s ://git.zx2c4.com/cgit/about/'>cgit %s</a> "
" (<a href='https://git-scm.com/'>git %s</a>) at " , cgit_version , git_version_string ) ;
html_txt( show_date ( time ( NULL ) , 0 , cgit_date_mode ( DATE_ISO8601 ) ) ) ;
htmlf ( " <div class='footer'>generated by <a href='http ://git.zx2c4.com/cgit/about/'>cgit %s</a> at " ,
cgit_version ) ;
cgit_print_date( time ( NULL ) , FMT_LONGDATE , ctx . cfg . local_time ) ;
html ( " </div> \n " ) ;
}
html ( " </div> <!-- id=cgit --> \n " ) ;
html ( " </body> \n </html> \n " ) ;
}
void cgit_print_error_page ( int code , const char * msg , const char * fmt , . . . )
{
va_list ap ;
ctx . page . expires = ctx . cfg . cache_dynamic_ttl ;
ctx . page . status = code ;
ctx . page . statusmsg = msg ;
cgit_print_layout_start ( ) ;
va_start ( ap , fmt ) ;
cgit_vprint_error ( fmt , ap ) ;
va_end ( ap ) ;
cgit_print_layout_end ( ) ;
}
void cgit_print_layout_start ( void )
{
cgit_print_http_headers ( ) ;
cgit_print_docstart ( ) ;
cgit_print_pageheader ( ) ;
}
void cgit_print_layout_end ( void )
{
cgit_print_docend ( ) ;
}
static void add_clone_urls ( void ( * fn ) ( const char * ) , char * txt , char * suffix )
{
struct strbuf * * url_list = strbuf_split_str ( txt , ' ' , 0 ) ;
@ -934,7 +792,7 @@ void cgit_add_clone_urls(void (*fn)(const char *))
add_clone_urls ( fn , ctx . cfg . clone_prefix , ctx . repo - > url ) ;
}
static int print_branch_option ( const char * refname , const struct object_id * oid ,
static int print_branch_option ( const char * refname , const unsigned char * sha1 ,
int flags , void * cb_data )
{
char * name = ( char * ) refname ;
@ -959,10 +817,10 @@ void cgit_add_hidden_formfields(int incl_head, int incl_search,
strcmp ( ctx . qry . head , ctx . repo - > defbranch ) )
html_hidden ( " h " , ctx . qry . head ) ;
if ( ctx . qry . oid )
html_hidden ( " id " , ctx . qry . oid ) ;
if ( ctx . qry . oid 2)
html_hidden ( " id2 " , ctx . qry . oid 2) ;
if ( ctx . qry . sha1 )
html_hidden ( " id " , ctx . qry . sha1 ) ;
if ( ctx . qry . sha 2)
html_hidden ( " id2 " , ctx . qry . sha 2) ;
if ( ctx . qry . showmsg )
html_hidden ( " showmsg " , " 1 " ) ;
@ -976,9 +834,6 @@ void cgit_add_hidden_formfields(int incl_head, int incl_search,
static const char * hc ( const char * page )
{
if ( ! ctx . qry . page )
return NULL ;
return strcmp ( ctx . qry . page , page ) ? NULL : " active " ;
}
@ -986,13 +841,12 @@ static void cgit_print_path_crumbs(char *path)
{
char * old_path = ctx . qry . path ;
char * p = path , * q , * end = path + strlen ( path ) ;
int levels = 0 ;
ctx . qry . path = NULL ;
cgit_self_link ( " root " , NULL , NULL ) ;
ctx . qry . path = p = path ;
while ( p < end ) {
if ( ! ( q = strchr ( p , ' / ' ) ) | | levels > 15 )
if ( ! ( q = strchr ( p , ' / ' ) ) )
q = end ;
* q = ' \0 ' ;
html_txt ( " / " ) ;
@ -1000,7 +854,6 @@ static void cgit_print_path_crumbs(char *path)
if ( q < end )
* q = ' / ' ;
p = q + 1 ;
+ + levels ;
}
ctx . qry . path = old_path ;
}
@ -1035,17 +888,15 @@ static void print_header(void)
if ( ctx . repo ) {
cgit_index_link ( " index " , NULL , NULL , NULL , NULL , 0 , 1 ) ;
html ( " : " ) ;
cgit_summary_link ( ctx . repo - > name , NULL , NULL , NULL ) ;
cgit_summary_link ( ctx . repo - > name , ctx . repo - > name , NULL , NULL ) ;
if ( ctx . env . authenticated ) {
html ( " </td><td class='form'> " ) ;
html ( " <form method='get' >\n " ) ;
html ( " <form method='get' action='' >\n " ) ;
cgit_add_hidden_formfields ( 0 , 1 , ctx . qry . page ) ;
html ( " <select name='h' onchange='this.form.submit();'> \n " ) ;
for_each_branch_ref ( print_branch_option , ctx . qry . head ) ;
if ( ctx . repo - > enable_remote_branches )
for_each_remote_ref ( print_branch_option , ctx . qry . head ) ;
html ( " </select> " ) ;
html ( " <input type='submit' value='switch'/>" ) ;
html ( " <input type='submit' name='' value='switch'/> " ) ;
html ( " </form> " ) ;
}
} else
@ -1056,16 +907,12 @@ static void print_header(void)
if ( ctx . repo ) {
html_txt ( ctx . repo - > desc ) ;
html ( " </td><td class='sub right'> " ) ;
if ( ctx . repo - > owner_filter ) {
cgit_open_filter ( ctx . repo - > owner_filter ) ;
html_txt ( ctx . repo - > owner ) ;
cgit_close_filter ( ctx . repo - > owner_filter ) ;
} else {
html_txt ( ctx . repo - > owner ) ;
}
html_txt ( ctx . repo - > owner ) ;
} else {
if ( ctx . cfg . root_desc )
html_txt ( ctx . cfg . root_desc ) ;
else if ( ctx . cfg . index_info )
html_include ( ctx . cfg . index_info ) ;
}
html ( " </td></tr></table> \n " ) ;
}
@ -1085,36 +932,24 @@ void cgit_print_pageheader(void)
cgit_summary_link ( " summary " , NULL , hc ( " summary " ) ,
ctx . qry . head ) ;
cgit_refs_link ( " refs " , NULL , hc ( " refs " ) , ctx . qry . head ,
ctx . qry . oid , NULL ) ;
ctx . qry . sha1 , NULL ) ;
cgit_log_link ( " log " , NULL , hc ( " log " ) , ctx . qry . head ,
NULL , ctx . qry . vpath , 0 , NULL , NULL ,
ctx . qry . showmsg , ctx . qry . follow ) ;
if ( ctx . qry . page & & ! strcmp ( ctx . qry . page , " blame " ) )
cgit_blame_link ( " blame " , NULL , hc ( " blame " ) , ctx . qry . head ,
ctx . qry . oid , ctx . qry . vpath ) ;
else
cgit_tree_link ( " tree " , NULL , hc ( " tree " ) , ctx . qry . head ,
ctx . qry . oid , ctx . qry . vpath ) ;
ctx . qry . showmsg ) ;
cgit_tree_link ( " tree " , NULL , hc ( " tree " ) , ctx . qry . head ,
ctx . qry . sha1 , ctx . qry . vpath ) ;
cgit_commit_link ( " commit " , NULL , hc ( " commit " ) ,
ctx . qry . head , ctx . qry . oid , ctx . qry . vpath ) ;
ctx . qry . head , ctx . qry . sha1 , ctx . qry . vpath ) ;
cgit_diff_link ( " diff " , NULL , hc ( " diff " ) , ctx . qry . head ,
ctx . qry . oid, ctx . qry . oid 2, ctx . qry . vpath ) ;
ctx . qry . sha1 , ctx . qry . sha2 , ctx . qry . vpath ) ;
if ( ctx . repo - > max_stats )
cgit_stats_link ( " stats " , NULL , hc ( " stats " ) ,
ctx . qry . head , ctx . qry . vpath ) ;
if ( ctx . repo - > homepage ) {
html ( " <a href=' " ) ;
html_attr ( ctx . repo - > homepage ) ;
html ( " '>homepage</a> " ) ;
}
html ( " </td><td class='form'> " ) ;
html ( " <form class='right' method='get' action=' " ) ;
if ( ctx . cfg . virtual_root ) {
char * fileurl = cgit_fileurl ( ctx . qry . repo , " log " ,
ctx . qry . vpath , NULL ) ;
html_url_path ( fileurl ) ;
free ( fileurl ) ;
}
if ( ctx . cfg . virtual_root )
html_url_path ( cgit_fileurl ( ctx . qry . repo , " log " ,
ctx . qry . vpath , NULL ) ) ;
html ( " '> \n " ) ;
cgit_add_hidden_formfields ( 1 , 0 , " log " ) ;
html ( " <select name='qt'> \n " ) ;
@ -1123,41 +958,31 @@ void cgit_print_pageheader(void)
html_option ( " committer " , " committer " , ctx . qry . grep ) ;
html_option ( " range " , " range " , ctx . qry . grep ) ;
html ( " </select> \n " ) ;
html ( " <input class='txt' type=' search ' size='10' name='q' value='" ) ;
html ( " <input class='txt' type=' text ' size='10' name='q' value='" ) ;
html_attr ( ctx . qry . search ) ;
html ( " '/> \n " ) ;
html ( " <input type='submit' value='search'/> \n " ) ;
html ( " </form> \n " ) ;
} else if ( ctx . env . authenticated ) {
char * currenturl = cgit_currenturl ( ) ;
site_link ( NULL , " index " , NULL , hc ( " repolist " ) , NULL , NULL , 0 , 1 ) ;
if ( ctx . cfg . root_readme )
site_link ( " about " , " about " , NULL , hc ( " about " ) ,
NULL , NULL , 0 , 1 ) ;
html ( " </td><td class='form'> " ) ;
html ( " <form method='get' action=' " ) ;
html_attr ( currenturl ) ;
html_attr ( cgit_currenturl ( ) ) ;
html ( " '> \n " ) ;
html ( " <input type=' search ' name='q' size='10' value='" ) ;
html ( " <input type=' text ' name='q' size='10' value='" ) ;
html_attr ( ctx . qry . search ) ;
html ( " '/> \n " ) ;
html ( " <input type='submit' value='search'/> \n " ) ;
html ( " </form> " ) ;
free ( currenturl ) ;
}
html ( " </td></tr></table> \n " ) ;
if ( ctx . env . authenticated & & ctx . repo & & ctx . qry. vpath ) {
if ( ctx . env . authenticated & & ctx . qry. vpath ) {
html ( " <div class='path'> " ) ;
html ( " path: " ) ;
cgit_print_path_crumbs ( ctx . qry . vpath ) ;
if ( ctx . cfg . enable_follow_links & & ! strcmp ( ctx . qry . page , " log " ) ) {
html ( " ( " ) ;
ctx . qry . follow = ! ctx . qry . follow ;
cgit_self_link ( ctx . qry . follow ? " follow " : " unfollow " ,
NULL , NULL ) ;
ctx . qry . follow = ! ctx . qry . follow ;
html ( " ) " ) ;
}
html ( " </div> " ) ;
}
html ( " <div class='content'> " ) ;
@ -1178,80 +1003,27 @@ void cgit_print_filemode(unsigned short mode)
html_fileperm ( mode ) ;
}
void cgit_ compose_snapshot_prefix( struct strbuf * filename , const char * base ,
const char * ref )
void cgit_ print_snapshot_links( const char * repo , const char * head ,
const char * hex , int snapshots )
{
struct object_id oid ;
/*
* Prettify snapshot names by stripping leading " v " or " V " if the tag
* name starts with { v , V } [ 0 - 9 ] and the prettify mapping is injective ,
* i . e . each stripped tag can be inverted without ambiguities .
*/
if ( get_oid ( fmt ( " refs/tags/%s " , ref ) , & oid ) = = 0 & &
( ref [ 0 ] = = ' v ' | | ref [ 0 ] = = ' V ' ) & & isdigit ( ref [ 1 ] ) & &
( ( get_oid ( fmt ( " refs/tags/%s " , ref + 1 ) , & oid ) = = 0 ) +
( get_oid ( fmt ( " refs/tags/v%s " , ref + 1 ) , & oid ) = = 0 ) +
( get_oid ( fmt ( " refs/tags/V%s " , ref + 1 ) , & oid ) = = 0 ) = = 1 ) )
ref + + ;
strbuf_addf ( filename , " %s-%s " , base , ref ) ;
}
void cgit_print_snapshot_links ( const struct cgit_repo * repo , const char * ref ,
const char * separator )
{
const struct cgit_snapshot_format * f ;
const struct cgit_snapshot_format * f ;
struct strbuf filename = STRBUF_INIT ;
const char * basename ;
size_t prefixlen ;
unsigned char sha1 [ 20 ] ;
basename = cgit_snapshot_prefix ( repo ) ;
if ( starts_with ( ref , basename ) )
strbuf_addstr ( & filename , ref ) ;
else
cgit_compose_snapshot_prefix ( & filename , basename , ref ) ;
if ( get_sha1 ( fmt ( " refs/tags/%s " , hex ) , sha1 ) = = 0 & &
( hex [ 0 ] = = ' v ' | | hex [ 0 ] = = ' V ' ) & & isdigit ( hex [ 1 ] ) )
hex + + ;
strbuf_addf ( & filename , " %s-%s " , cgit_repobasename ( repo ) , hex ) ;
prefixlen = filename . len ;
for ( f = cgit_snapshot_formats ; f - > suffix ; f + + ) {
if ( ! ( repo- > snapshots & cgit_snapshot_format_bit ( f ) ) )
if ( ! ( snapshots & f - > bit ) )
continue ;
strbuf_setlen ( & filename , prefixlen ) ;
strbuf_addstr ( & filename , f - > suffix ) ;
cgit_snapshot_link ( filename . buf , NULL , NULL , NULL , NULL ,
filename . buf ) ;
if ( cgit_snapshot_get_sig ( ref , f ) ) {
strbuf_addstr ( & filename , " .asc " ) ;
html ( " ( " ) ;
cgit_snapshot_link ( " sig " , NULL , NULL , NULL , NULL ,
filename . buf ) ;
html ( " ) " ) ;
} else if ( starts_with ( f - > suffix , " .tar " ) & & cgit_snapshot_get_sig ( ref , & cgit_snapshot_formats [ 0 ] ) ) {
strbuf_setlen ( & filename , strlen ( filename . buf ) - strlen ( f - > suffix ) ) ;
strbuf_addstr ( & filename , " .tar.asc " ) ;
html ( " ( " ) ;
cgit_snapshot_link ( " sig " , NULL , NULL , NULL , NULL ,
filename . buf ) ;
html ( " ) " ) ;
}
html ( separator ) ;
html ( " <br/> " ) ;
}
strbuf_release ( & filename ) ;
}
void cgit_set_title_from_path ( const char * path )
{
struct strbuf sb = STRBUF_INIT ;
const char * slash , * last_slash ;
if ( ! path )
return ;
for ( last_slash = path + strlen ( path ) ; ( slash = memrchr ( path , ' / ' , last_slash - path ) ) ! = NULL ; last_slash = slash ) {
strbuf_add ( & sb , slash + 1 , last_slash - slash - 1 ) ;
strbuf_addstr ( & sb , " \xc2 \xab " ) ;
}
strbuf_add ( & sb , path , last_slash - path ) ;
strbuf_addf ( & sb , " - %s " , ctx . page . title ) ;
ctx . page . title = strbuf_detach ( & sb , NULL ) ;
}