diff options
author | kx <kx@radix.pro> | 2023-03-24 03:55:33 +0300 |
---|---|---|
committer | kx <kx@radix.pro> | 2023-03-24 03:55:33 +0300 |
commit | bfc1508d26c89c9a36d2d9a827fe2c4ed128884d (patch) | |
tree | 8d41298a7072a3e289e4912f77ece75cbea1bd54 /csvncgi/ui-log.c | |
parent | c836ae3775cf72f17e0b7e3792d156fdb389bee3 (diff) | |
download | csvn-ui-bfc1508d26c89c9a36d2d9a827fe2c4ed128884d.tar.xz |
Version 0.1.4
Diffstat (limited to 'csvncgi/ui-log.c')
-rw-r--r-- | csvncgi/ui-log.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/csvncgi/ui-log.c b/csvncgi/ui-log.c new file mode 100644 index 0000000..d0c17b6 --- /dev/null +++ b/csvncgi/ui-log.c @@ -0,0 +1,343 @@ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <sys/sysinfo.h> +#include <sys/types.h> +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#else +#include <stdint.h> +#endif +#include <stddef.h> /* offsetof(3) */ +#include <dirent.h> +#include <sys/stat.h> /* chmod(2) */ +#include <sys/file.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <limits.h> +#include <string.h> /* strdup(3) */ +#include <libgen.h> /* basename(3) */ +#include <ctype.h> /* tolower(3) */ +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <pwd.h> +#include <grp.h> +#include <stdarg.h> +#include <locale.h> +#include <unistd.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> + +#include <nls.h> + +#include <defs.h> + +#include <fatal.h> +#include <http.h> +#include <html.h> + +#include <dlist.h> +#include <strbuf.h> +#include <repolist.h> +#include <wrapper.h> +#include <system.h> +#include <date.h> + +#include <ctx.h> +#include <ui-shared.h> + + +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, " <div class=\"repo-log-header\">\n" ); + strbuf_addf( sb, " <div class=\"row\">\n" ); + strbuf_addf( sb, " <div class=\"col-date\"><div class=\"log-date\">Date</div></div>\n" ); + strbuf_addf( sb, " <div class=\"col-cmsg\"><div class=\"log-cmsg trunc\">Commit Message</div></div>\n" ); + strbuf_addf( sb, " <div class=\"col-rev\"><div class=\"log-rev trunc\">Rev</div></div>\n" ); + strbuf_addf( sb, " <div class=\"col-author\"><div class=\"log-author trunc\">Author</div></div>\n" ); + strbuf_addf( sb, " </div>\n" ); + strbuf_addf( sb, " </div>\n\n" ); + + strbuf_addf( sb, " <div class=\"log\">\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, " <div class=\"row\">\n" ); + if( time != -1 ) + { + strbuf_addf( sb, " <div class=\"col-date\"><div onclick=\"trunc(this)\" class=\"log-date trunc\">" ); + csvn_print_age( sb, time, 0, 0 ); + strbuf_addf( sb, "</div></div>\n" ); + } + else + { + strbuf_addf( sb, " <div class=\"col-date\"><div onclick=\"trunc(this)\" class=\"log-date trunc\">unknown</div></div>\n" ); + } + strbuf_addf( sb, " <div class=\"col-cmsg\"><div onclick=\"trunc(this)\" class=\"log-cmsg trunc\">%s</div></div>\n", (char *)cmsg ); + if( query_string && *query_string ) + { + strbuf_addf( sb, " <div class=\"col-rev\"><div onclick=\"trunc(this)\" class=\"log-rev trunc\"><a title=\"Compare with Previous\" href=\"/%s%s/?op=diff&rev=%s&%s\">%s</a></div></div>\n", ctx.repo.name, path, (char *)revision, query_string, (char *)revision ); + } + else + { + strbuf_addf( sb, " <div class=\"col-rev\"><div onclick=\"trunc(this)\" class=\"log-rev trunc\"><a title=\"Compare with Previous\" href=\"/%s%s/?op=diff&rev=%s\">%s</a></div></div>\n", ctx.repo.name, path, (char *)revision, (char *)revision ); + } + strbuf_addf( sb, " <div class=\"col-author\"><div onclick=\"trunc(this)\" class=\"log-author trunc\">%s</div></div>\n", (char *)author ); + strbuf_addf( sb, " </div>\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, " </div> <!-- End of Log -->\n\n" ); + + /******************************** + Print log direction: + */ + reminder = count - ctx.query.ofs - printed; + if( page_size < count ) + { + int prev, next; + + strbuf_addf( sb, " <div class=\"log-direction\">\n" ); + strbuf_addf( sb, " <div class=\"row\">\n" ); + strbuf_addf( sb, " <div class=\"left col-prev\">\n" ); + strbuf_addf( sb, " <div class=\"prev-log-direction\">\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 ) + strbuf_addf( sb, " <a href=\"/%s%s/?ofs=%d&%s\">≪ Prev</a>\n", ctx.repo.name, path, prev, ctx.env.query_string ); + else + strbuf_addf( sb, " <a href=\"/%s%s/?ofs=%d\">≪ Prev</a>\n", ctx.repo.name, path, prev ); + } + + strbuf_addf( sb, " </div>\n" ); + strbuf_addf( sb, " </div>\n" ); + strbuf_addf( sb, " <div class=\"right col-next\">\n" ); + strbuf_addf( sb, " <div class=\"next-log-direction\">\n" ); + + if( reminder ) + { + next = ctx.query.ofs + page_size; + + if( ctx.env.query_string && *ctx.env.query_string ) + strbuf_addf( sb, " <a href=\"/%s%s/?ofs=%d&%s\">Next ≫</a>\n", ctx.repo.name, path, next, ctx.env.query_string ); + else + strbuf_addf( sb, " <a href=\"/%s%s/?ofs=%d\">Next ≫</a>\n", ctx.repo.name, path, next ); + } + + strbuf_addf( sb, " </div>\n" ); + strbuf_addf( sb, " </div>\n" ); + strbuf_addf( sb, " </div>\n" ); + strbuf_addf( sb, " </div>\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 *repo_path = ctx.repo.name; + 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 cmd[1024]; + struct strbuf buf = STRBUF_INIT; + pid_t p = (pid_t) -1; + int rc; + + if( revision ) + snprintf( (char *)&cmd[0], 1024, + "svn log --revision %d:0 --xml %s/%s%s 2>/dev/null", + revision, co_prefix, repo_path, path ); + else + snprintf( (char *)&cmd[0], 1024, + "svn log --xml %s/%s%s 2>/dev/null", + co_prefix, repo_path, 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, " <div class=\"content segment\">\n" ); + strbuf_addf( &buf, " <div class=\"container\">\n" ); + strbuf_addf( &buf, " <div class=\"csvn-main-content\">\n" ); + + if( ctx.repo.name ) + { + csvn_print_log( &buf, ctx.repo.relative_path, ctx.query.rev ); + } + else + { + strbuf_addf( &buf, " <h1>Requested resource cannot be shown</h1>\n" ); + strbuf_addf( &buf, " <p class='leading'>Repository '%s' not found.</p>\n", ctx.repo.name ); + } + + strbuf_addf( &buf, " </div> <!-- End of csvn-main-content -->\n" ); + strbuf_addf( &buf, " </div> <!-- End of container -->\n" ); + strbuf_addf( &buf, " </div> <!-- End of content segment -->\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 ); +} |