#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_INTTYPES_H #include #else #include #endif #include /* offsetof(3) */ #include #include /* chmod(2) */ #include #include #include #include #include /* strdup(3) */ #include /* basename(3) */ #include /* tolower(3) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void xml_csvn_log( struct strbuf *sb, const struct strbuf *buf, const char *relative_path ) { xmlDocPtr doc = NULL; xmlNode *root = NULL; char *path = NULL; int count = 0, printed = 0, reminder = 0, page_size = 200; if( !sb || !sb->len || !buf || !buf->buf ) return; if( relative_path && *relative_path ) { path = (char *)xmalloc( strlen( relative_path ) + 2 ); path[0] = '/'; sprintf( (char *)&path[1], relative_path ); } else { path = (char *)xmalloc( 1 ); path[0] = '\0'; } page_size = atoi( ctx.vars.page_size ); LIBXML_TEST_VERSION doc = xmlReadMemory( buf->buf, buf->len, "log.xml", NULL, 0 ); if( !doc ) { html_fatal( "cannot parse svn log.xml" ); return; } root = xmlDocGetRootElement( doc ); if( !root ) { free( path ); xmlFreeDoc( doc ); xmlCleanupParser(); return; } if( !strcmp( "log", (char *)root->name ) ) { xmlNode *node = NULL; strbuf_addstr( sb, "\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
Date
\n" ); strbuf_addf( sb, "
Commit Message
\n" ); strbuf_addf( sb, "
Rev
\n" ); strbuf_addf( sb, "
Author
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n\n" ); strbuf_addf( sb, "
\n\n" ); /************************** Print directories first: */ for( node = root->children; node; node = node->next ) { if( node->type == XML_ELEMENT_NODE && !strcmp( "logentry", (char *)node->name ) ) { xmlNode *param = NULL; xmlChar *date = NULL, *cmsg = NULL, *revision = NULL, *author = NULL; revision = xmlGetProp( node, (const unsigned char *)"revision" ); for( param = node->children; param; param= param->next ) { if( param->type == XML_ELEMENT_NODE && !strcmp( "date", (char *)param->name ) ) { date = xmlNodeGetContent( param ); } if( param->type == XML_ELEMENT_NODE && !strcmp( "msg", (char *)param->name ) ) { cmsg = xmlNodeGetContent( param ); } if( param->type == XML_ELEMENT_NODE && !strcmp( "author", (char *)param->name ) ) { author = xmlNodeGetContent( param ); } } /* End for entry parameters */ if( date && cmsg && revision && author ) { struct tm tm; time_t time = -1; const char *query_string = ctx_remove_query_param( ctx.env.query_string, "rev" ); query_string = ctx_remove_query_param( query_string, "op" ); time = parse_date( &tm, (const char *)date ); ++count; if( count > ctx.query.ofs && printed < page_size ) { strbuf_addf( sb, "
\n" ); if( time != -1 ) { strbuf_addf( sb, "
" ); csvn_print_age( sb, time, 0, 0 ); strbuf_addf( sb, "
\n" ); } else { strbuf_addf( sb, "
unknown
\n" ); } strbuf_addf( sb, "
%s
\n", (char *)cmsg ); if( query_string && *query_string ) { if( ctx.repo.repo_root && *ctx.repo.repo_root ) { strbuf_addf( sb, " \n", ctx.repo.repo_root, ctx.repo.name, path, (char *)revision, query_string, (char *)revision ); } else { strbuf_addf( sb, " \n", ctx.repo.name, path, (char *)revision, query_string, (char *)revision ); } } else { if( ctx.repo.repo_root && *ctx.repo.repo_root ) { strbuf_addf( sb, " \n", ctx.repo.repo_root, path, ctx.repo.name, path, (char *)revision, (char *)revision ); } else { strbuf_addf( sb, " \n", ctx.repo.name, path, (char *)revision, (char *)revision ); } } strbuf_addf( sb, "
%s
\n", (char *)author ); strbuf_addf( sb, "
\n\n" ); ++printed; } xmlFree( date ); xmlFree( cmsg ); xmlFree( revision ); xmlFree( author ); } else { if( date ) xmlFree( date ); if( cmsg ) xmlFree( cmsg ); if( revision ) xmlFree( revision ); if( author ) xmlFree( author ); } } } strbuf_addf( sb, "
\n\n" ); /******************************** Print log direction: */ reminder = count - ctx.query.ofs - printed; if( page_size < count ) { int prev, next; strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); if( ctx.query.ofs ) { prev = ctx.query.ofs - page_size; if( prev < 0 ) prev = 0; if( ctx.env.query_string && *ctx.env.query_string ) { if( ctx.repo.repo_root && *ctx.repo.repo_root ) { strbuf_addf( sb, " ≪  Prev\n", ctx.repo.repo_root, ctx.repo.name, path, prev, ctx.env.query_string ); } else { strbuf_addf( sb, " ≪  Prev\n", ctx.repo.name, path, prev, ctx.env.query_string ); } } else { if( ctx.repo.repo_root && *ctx.repo.repo_root ) { strbuf_addf( sb, " ≪  Prev\n", ctx.repo.repo_root, ctx.repo.name, path, prev ); } else { strbuf_addf( sb, " ≪  Prev\n", ctx.repo.name, path, prev ); } } } strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); if( reminder ) { next = ctx.query.ofs + page_size; if( ctx.env.query_string && *ctx.env.query_string ) { if( ctx.repo.repo_root && *ctx.repo.repo_root ) { strbuf_addf( sb, " Next  ≫\n", ctx.repo.repo_root, ctx.repo.name, path, next, ctx.env.query_string ); } else { strbuf_addf( sb, " Next  ≫\n", ctx.repo.name, path, next, ctx.env.query_string ); } } else { if( ctx.repo.repo_root && *ctx.repo.repo_root ) { strbuf_addf( sb, " Next  ≫\n", ctx.repo.repo_root, ctx.repo.name, path, next ); } else { strbuf_addf( sb, " Next  ≫\n", ctx.repo.name, path, next ); } } } strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); strbuf_addf( sb, "
\n" ); } /* End of printing log direction. ********************************/ } free( path ); xmlFreeDoc(doc); xmlCleanupParser(); } static void csvn_print_log( struct strbuf *sb, const char *relative_path, int revision ) { const char *co_prefix = ctx.repo.checkout_ro_prefix; const char *name = ctx.repo.name; const char *repo_root = ctx.repo.repo_root; char *path = NULL; if( !sb ) return; if( relative_path && *relative_path ) { path = (char *)xmalloc( strlen( relative_path ) + 2 ); path[0] = '/'; sprintf( (char *)&path[1], relative_path ); } else { path = (char *)xmalloc( 1 ); path[0] = '\0'; } if( co_prefix ) { char repo_path[PATH_MAX] = { 0 }; char cmd[PATH_MAX]; struct strbuf buf = STRBUF_INIT; pid_t p = (pid_t) -1; int rc; if( repo_root && *repo_root ) { strcat( (char *)&repo_path[0], repo_root ); strcat( (char *)&repo_path[0], "/" ); } strcat( (char *)&repo_path[0], name ); if( revision ) snprintf( (char *)&cmd[0], 1024, "svn log --revision %d:0 --xml %s/%s%s 2>/dev/null", revision, co_prefix, (char *)&repo_path[0], path ); else snprintf( (char *)&cmd[0], 1024, "svn log --xml %s/%s%s 2>/dev/null", co_prefix, (char *)&repo_path[0], path ); p = sys_exec_command( &buf, cmd ); rc = sys_wait_command( p, NULL ); if( rc != 0 ) { strbuf_release( &buf ); free( path ); return; } xml_csvn_log( sb, (const struct strbuf *)&buf, relative_path ); strbuf_release( &buf ); } free( path ); return; } void csvn_print_log_page( void ) { FILE *fp; struct strbuf buf = STRBUF_INIT; fp = xfopen( ctx.page.header, "r" ); (void)strbuf_env_fread( &buf, fp ); fclose( fp ); strbuf_addf( &buf, "
\n" ); strbuf_addf( &buf, "
\n" ); strbuf_addf( &buf, "
\n" ); if( ctx.repo.name ) { csvn_print_log( &buf, ctx.repo.relative_path, ctx.query.rev ); } else { strbuf_addf( &buf, "

Requested resource cannot be shown

\n" ); strbuf_addf( &buf, "

Repository '%s' not found.

\n", ctx.repo.name ); } strbuf_addf( &buf, "
\n" ); strbuf_addf( &buf, "
\n" ); strbuf_addf( &buf, "
\n" ); fp = xfopen( ctx.page.footer, "r" ); (void)strbuf_env_fread( &buf, fp ); fclose( fp ); ctx.page.size = buf.len; csvn_print_http_headers(); strbuf_write( &buf, STDOUT_FILENO ); strbuf_release( &buf ); }