cSvn-UI for SVN Repositories

cGit-UI – is a web interface for Subversion (SVN) Repositories. cSvn CGI script is writen in C and therefore it's fast enough

6 Commits   0 Branches   2 Tags
bfc1508d (kx 2023-03-24 03:55:33 +0300    1) 
bfc1508d (kx 2023-03-24 03:55:33 +0300    2) #ifdef HAVE_CONFIG_H
bfc1508d (kx 2023-03-24 03:55:33 +0300    3) #include <config.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300    4) #endif
bfc1508d (kx 2023-03-24 03:55:33 +0300    5) 
bfc1508d (kx 2023-03-24 03:55:33 +0300    6) #include <stdlib.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300    7) #include <stdio.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300    8) #include <sys/sysinfo.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300    9) #include <sys/types.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   10) #ifdef HAVE_INTTYPES_H
bfc1508d (kx 2023-03-24 03:55:33 +0300   11) #include <inttypes.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   12) #else
bfc1508d (kx 2023-03-24 03:55:33 +0300   13) #include <stdint.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   14) #endif
bfc1508d (kx 2023-03-24 03:55:33 +0300   15) #include <stddef.h>   /* offsetof(3) */
bfc1508d (kx 2023-03-24 03:55:33 +0300   16) #include <dirent.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   17) #include <sys/stat.h> /* chmod(2)    */
bfc1508d (kx 2023-03-24 03:55:33 +0300   18) #include <sys/file.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   19) #include <sys/mman.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   20) #include <fcntl.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   21) #include <limits.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   22) #include <string.h>   /* strdup(3)   */
bfc1508d (kx 2023-03-24 03:55:33 +0300   23) #include <libgen.h>   /* basename(3) */
bfc1508d (kx 2023-03-24 03:55:33 +0300   24) #include <ctype.h>    /* tolower(3)  */
bfc1508d (kx 2023-03-24 03:55:33 +0300   25) #include <errno.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   26) #include <time.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   27) #include <sys/time.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   28) #include <pwd.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   29) #include <grp.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   30) #include <stdarg.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   31) #include <locale.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   32) #include <math.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   33) #include <unistd.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   34) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   35) #include <libxml/parser.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   36) #include <libxml/tree.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   37) #include <magic.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   38) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   39) #include <nls.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   40) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   41) #include <defs.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   42) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   43) #include <fatal.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   44) #include <http.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   45) #include <html.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   46) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   47) #include <dlist.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   48) #include <strbuf.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   49) #include <repolist.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   50) #include <wrapper.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   51) #include <system.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   52) #include <date.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   53) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   54) #include <ctx.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   55) #include <ui-shared.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300   56) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   57) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   58) void csvn_change_location( const char *location )
bfc1508d (kx 2023-03-24 03:55:33 +0300   59) {
bfc1508d (kx 2023-03-24 03:55:33 +0300   60)   if( ctx.env.no_http && !strcmp( ctx.env.no_http, "1" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300   61)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300   62) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   63)   htmlf( "Status: %d %s\n", 302, "Found" );
bfc1508d (kx 2023-03-24 03:55:33 +0300   64)   htmlf( "Location: %s\n", location );
bfc1508d (kx 2023-03-24 03:55:33 +0300   65)   html( "\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300   66) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   67)   exit( 0 );
bfc1508d (kx 2023-03-24 03:55:33 +0300   68) }
bfc1508d (kx 2023-03-24 03:55:33 +0300   69) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   70) void csvn_print_http_headers( void )
bfc1508d (kx 2023-03-24 03:55:33 +0300   71) {
bfc1508d (kx 2023-03-24 03:55:33 +0300   72)   if( ctx.env.no_http && !strcmp( ctx.env.no_http, "1" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300   73)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300   74) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   75)   /*****************************************************
bfc1508d (kx 2023-03-24 03:55:33 +0300   76)     If we pass 'Status: 200 OK' header then nginx+uWsgi
bfc1508d (kx 2023-03-24 03:55:33 +0300   77)     will duplicate other headers randomly 
bfc1508d (kx 2023-03-24 03:55:33 +0300   78)    */
bfc1508d (kx 2023-03-24 03:55:33 +0300   79)   if( ctx.page.status != 200 )
bfc1508d (kx 2023-03-24 03:55:33 +0300   80)     htmlf( "Status: %d %s\n", ctx.page.status, ctx.page.status_message );
bfc1508d (kx 2023-03-24 03:55:33 +0300   81) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   82)   if( ctx.page.mimetype && ctx.page.charset )
bfc1508d (kx 2023-03-24 03:55:33 +0300   83)     htmlf( "Content-Type: %s; charset=%s\n", ctx.page.mimetype, ctx.page.charset );
bfc1508d (kx 2023-03-24 03:55:33 +0300   84)   else if( ctx.page.mimetype )
bfc1508d (kx 2023-03-24 03:55:33 +0300   85)     htmlf( "Content-Type: %s\n", ctx.page.mimetype );
bfc1508d (kx 2023-03-24 03:55:33 +0300   86) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   87)   if( ctx.page.size )
bfc1508d (kx 2023-03-24 03:55:33 +0300   88)     htmlf( "Content-Length: %zd\n", ctx.page.size );
bfc1508d (kx 2023-03-24 03:55:33 +0300   89) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   90)   if( !ctx.env.authenticated )
bfc1508d (kx 2023-03-24 03:55:33 +0300   91)     html( "Cache-Control: no-cache, no-store\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300   92) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   93)   htmlf( "Last-Modified: %s\n", http_date( ctx.page.modified ) );
bfc1508d (kx 2023-03-24 03:55:33 +0300   94)   htmlf( "Expires: %s\n", http_date( ctx.page.expires ) );
bfc1508d (kx 2023-03-24 03:55:33 +0300   95) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   96)   html( "\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300   97) }
bfc1508d (kx 2023-03-24 03:55:33 +0300   98) 
bfc1508d (kx 2023-03-24 03:55:33 +0300   99) const struct date_mode *csvn_date_mode( enum date_mode_type type )
bfc1508d (kx 2023-03-24 03:55:33 +0300  100) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  101)   static struct date_mode mode;
bfc1508d (kx 2023-03-24 03:55:33 +0300  102)   mode.type = type;
bfc1508d (kx 2023-03-24 03:55:33 +0300  103)   mode.local = 0; /* may be from ctx.cfg.local_time; =0/1 */
bfc1508d (kx 2023-03-24 03:55:33 +0300  104)   return &mode;
bfc1508d (kx 2023-03-24 03:55:33 +0300  105) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  106) /* OR data_mode_from_type():
bfc1508d (kx 2023-03-24 03:55:33 +0300  107)    struct date_mode *mode = DATE_MODE( DATE_ISO8601 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  108)    but in this case mode.local is always zero!
bfc1508d (kx 2023-03-24 03:55:33 +0300  109)  */
bfc1508d (kx 2023-03-24 03:55:33 +0300  110) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  111) static void print_rel_date( struct strbuf *sb, time_t t, int tz,
bfc1508d (kx 2023-03-24 03:55:33 +0300  112)                             const char *class, const char *value )
bfc1508d (kx 2023-03-24 03:55:33 +0300  113) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  114)   if( !sb || !t ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  115) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  116)   strbuf_addf( sb, "<span class='%s' title='", class );
bfc1508d (kx 2023-03-24 03:55:33 +0300  117)   show_date( sb, t, tz, csvn_date_mode( DATE_ISO8601 ) );
bfc1508d (kx 2023-03-24 03:55:33 +0300  118)   strbuf_addf( sb, "'>%s</span>", value );
bfc1508d (kx 2023-03-24 03:55:33 +0300  119) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  120) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  121) void csvn_print_age( struct strbuf *sb, time_t t, int tz, time_t max_relative )
bfc1508d (kx 2023-03-24 03:55:33 +0300  122) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  123)   time_t now, secs;
bfc1508d (kx 2023-03-24 03:55:33 +0300  124)   char buf[32] = { 0 };
bfc1508d (kx 2023-03-24 03:55:33 +0300  125)   size_t val;
bfc1508d (kx 2023-03-24 03:55:33 +0300  126) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  127)   if( !sb || !t ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  128) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  129)   now = time( NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  130)   secs = now - t;
bfc1508d (kx 2023-03-24 03:55:33 +0300  131)   if( secs < 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  132)     secs = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  133) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  134)   if( secs > max_relative && max_relative >= 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  135)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  136) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  137)     strbuf_addstr( sb, "<span title='" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  138)     show_date( sb, t, tz, csvn_date_mode( DATE_ISO8601 ) );
bfc1508d (kx 2023-03-24 03:55:33 +0300  139)     strbuf_addstr( sb, "'>" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  140)     show_date( sb, t, tz, csvn_date_mode( DATE_SHORT ) );
bfc1508d (kx 2023-03-24 03:55:33 +0300  141)     strbuf_addstr( sb, "</span>" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  142)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  143)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  144) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  145)   if( secs < TM_HOUR * 2 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  146)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  147)     val = (size_t)round(secs * 1.0 / TM_MIN);
bfc1508d (kx 2023-03-24 03:55:33 +0300  148)     snprintf( (char *)&buf[0], 32, Q_("%"PRIdMAX" minute", "%"PRIdMAX" minutes", val), val );
bfc1508d (kx 2023-03-24 03:55:33 +0300  149)     print_rel_date( sb, t, tz, "age-mins", (const char *)&buf[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  150)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  151)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  152)   if( secs < TM_DAY * 2 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  153)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  154)     val = (size_t)round(secs * 1.0 / TM_HOUR);
bfc1508d (kx 2023-03-24 03:55:33 +0300  155)     snprintf( (char *)&buf[0], 32, Q_("%"PRIdMAX" hour", "%"PRIdMAX" hours", val), val );
bfc1508d (kx 2023-03-24 03:55:33 +0300  156)     print_rel_date( sb, t, tz, "age-hours", (const char *)&buf[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  157)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  158)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  159)   if( secs < TM_WEEK * 2 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  160)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  161)     val = (size_t)round(secs * 1.0 / TM_DAY);
bfc1508d (kx 2023-03-24 03:55:33 +0300  162)     snprintf( (char *)&buf[0], 32, Q_("%"PRIdMAX" day", "%"PRIdMAX" days", val), val );
bfc1508d (kx 2023-03-24 03:55:33 +0300  163)     print_rel_date( sb, t, tz, "age-days", (const char *)&buf[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  164)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  165)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  166)   if( secs < TM_MONTH * 2 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  167)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  168)     val = (size_t)round(secs * 1.0 / TM_WEEK);
bfc1508d (kx 2023-03-24 03:55:33 +0300  169)     snprintf( (char *)&buf[0], 32, Q_("%"PRIdMAX" week", "%"PRIdMAX" weeks", val), val );
bfc1508d (kx 2023-03-24 03:55:33 +0300  170)     print_rel_date( sb, t, tz, "age-weeks", (const char *)&buf[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  171)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  172)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  173)   if( secs < TM_YEAR * 2 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  174)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  175)     val = (size_t)round(secs * 1.0 / TM_MONTH);
bfc1508d (kx 2023-03-24 03:55:33 +0300  176)     snprintf( (char *)&buf[0], 32, Q_("%"PRIdMAX" month", "%"PRIdMAX" months", val), val );
bfc1508d (kx 2023-03-24 03:55:33 +0300  177)     print_rel_date( sb, t, tz, "age-months", (const char *)&buf[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  178)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  179)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  180) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  181)   val = (size_t)round(secs * 1.0 / TM_YEAR);
bfc1508d (kx 2023-03-24 03:55:33 +0300  182)   snprintf( (char *)&buf[0], 32, Q_("%"PRIdMAX" year", "%"PRIdMAX" years", val), val );
bfc1508d (kx 2023-03-24 03:55:33 +0300  183)   print_rel_date( sb, t, tz, "age-years", (const char *)&buf[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  184) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  185) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  186) void csvn_search_repo( const char *path )
bfc1508d (kx 2023-03-24 03:55:33 +0300  187) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  188)   struct repo *repo = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  189) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  190)   if( !path || !*path ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  191) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  192)   repo = lookup_repo( config, path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  193)   if( repo )
bfc1508d (kx 2023-03-24 03:55:33 +0300  194)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  195)     int position = repo_position( config, repo );
bfc1508d (kx 2023-03-24 03:55:33 +0300  196)     if( position != -1 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  197)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  198)       char location[1024] = { 0 };
bfc1508d (kx 2023-03-24 03:55:33 +0300  199) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  200)       sprintf( (char *)&location[0], "/?ofs=%d", position );
bfc1508d (kx 2023-03-24 03:55:33 +0300  201)       csvn_change_location( (const char *)&location[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  202)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  203)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  204) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  205) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  206) size_t csvn_repo_last_changed_revision( struct strbuf *sb, struct repo *repo )
bfc1508d (kx 2023-03-24 03:55:33 +0300  207) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  208)   struct variable  ro_prefix = { (unsigned char *)"checkout-prefix-readonly", { 0 }, DT_PATH };
bfc1508d (kx 2023-03-24 03:55:33 +0300  209)   struct variable *prefix = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  210) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  211)   if( !repo || !repo->path ) return 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  212) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  213)   prefix = lookup( repo, &ro_prefix );
bfc1508d (kx 2023-03-24 03:55:33 +0300  214)   if( prefix )
bfc1508d (kx 2023-03-24 03:55:33 +0300  215)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  216)     char cmd[1024];
bfc1508d (kx 2023-03-24 03:55:33 +0300  217)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  218)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  219) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  220)     snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  221)               "svn info --show-item last-changed-revision --no-newline %s/%s/ 2>/dev/null",
bfc1508d (kx 2023-03-24 03:55:33 +0300  222)               prefix->_v.vptr, repo->path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  223)     p = sys_exec_command( sb, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  224)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  225)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  226)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  227)       return 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  228)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  229)     strbuf_trim( sb );
bfc1508d (kx 2023-03-24 03:55:33 +0300  230)     return sb->len;
bfc1508d (kx 2023-03-24 03:55:33 +0300  231)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  232)   return 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  233) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  234) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  235) time_t csvn_repo_last_changed_time( struct repo *repo )
bfc1508d (kx 2023-03-24 03:55:33 +0300  236) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  237)   struct variable  ro_prefix = { (unsigned char *)"checkout-prefix-readonly", { 0 }, DT_PATH };
bfc1508d (kx 2023-03-24 03:55:33 +0300  238)   struct variable *prefix = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  239)   time_t ret = -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  240) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  241)   if( !repo || !repo->path ) return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300  242) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  243)   prefix = lookup( repo, &ro_prefix );
bfc1508d (kx 2023-03-24 03:55:33 +0300  244)   if( prefix )
bfc1508d (kx 2023-03-24 03:55:33 +0300  245)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  246)     char cmd[1024];
bfc1508d (kx 2023-03-24 03:55:33 +0300  247)     struct tm tm;
bfc1508d (kx 2023-03-24 03:55:33 +0300  248)     time_t    time = -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  249)     struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  250)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  251)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  252) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  253)     snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  254)               "svn info --show-item last-changed-date --no-newline %s/%s/ 2>/dev/null",
bfc1508d (kx 2023-03-24 03:55:33 +0300  255)               prefix->_v.vptr, repo->path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  256)     p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  257)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  258)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  259)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  260)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  261)       return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300  262)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  263) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  264)     strbuf_trim( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  265)     time = parse_date( &tm, (const char *)buf.buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  266) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  267)     if( time != -1 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  268)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  269)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  270)       return time;
bfc1508d (kx 2023-03-24 03:55:33 +0300  271)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  272) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  273)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  274)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  275)   return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300  276) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  277) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  278) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  279) static xmlNode *xml_find_node_by_name( xmlNode *root, const char *name )
bfc1508d (kx 2023-03-24 03:55:33 +0300  280) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  281)   xmlNode *node = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  282)   xmlNode *ret  = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  283) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  284)   if( !name || !*name || !root || !root->children ) return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300  285) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  286)   for( node = root->children; node; node = node->next )
bfc1508d (kx 2023-03-24 03:55:33 +0300  287)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  288)     if( node->type == XML_ELEMENT_NODE )
bfc1508d (kx 2023-03-24 03:55:33 +0300  289)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  290)       if( !strcmp( (char *)name, (char *)node->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  291)       {
bfc1508d (kx 2023-03-24 03:55:33 +0300  292)         return node;
bfc1508d (kx 2023-03-24 03:55:33 +0300  293)       }
bfc1508d (kx 2023-03-24 03:55:33 +0300  294)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  295)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  296)   return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300  297) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  298) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  299) static void xml_csvn_info( struct strbuf *sb, struct csvn_info *info )
bfc1508d (kx 2023-03-24 03:55:33 +0300  300) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  301)   xmlDocPtr doc = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  302)   xmlNode *root = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  303) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  304)   if( !sb || !sb->len || !info ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  305) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  306)   LIBXML_TEST_VERSION
bfc1508d (kx 2023-03-24 03:55:33 +0300  307) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  308)   doc = xmlReadMemory( sb->buf, sb->len, "info.xml", NULL, 0 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  309)   if( !doc )
bfc1508d (kx 2023-03-24 03:55:33 +0300  310)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  311)     html_fatal( "cannot parse svn info.xml" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  312)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  313)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  314) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  315)   root = xmlDocGetRootElement( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  316)   if( !root )
bfc1508d (kx 2023-03-24 03:55:33 +0300  317)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  318)     xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  319)     xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  320)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  321)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  322) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  323)   if( !strcmp( "info", (char *)root->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  324)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  325)     xmlNode *entry = NULL, *commit  = NULL, *cnode   = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  326)     xmlChar *content = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  327) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  328)     entry = xml_find_node_by_name( root, "entry" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  329)     if( !entry )
bfc1508d (kx 2023-03-24 03:55:33 +0300  330)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  331)       xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  332)       xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  333)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  334)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  335)     content = xmlGetProp( entry, (const unsigned char *)"kind" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  336)     if( !content )
bfc1508d (kx 2023-03-24 03:55:33 +0300  337)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  338)       xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  339)       xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  340)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  341)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  342)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  343)       if( !strcmp( (char *)content, "dir" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  344)         info->kind = KIND_DIR;
bfc1508d (kx 2023-03-24 03:55:33 +0300  345)       else if( !strcmp( (char *)content, "file" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  346)         info->kind = KIND_FILE;
bfc1508d (kx 2023-03-24 03:55:33 +0300  347)       else
bfc1508d (kx 2023-03-24 03:55:33 +0300  348)         info->kind = KIND_UNKNOWN;
bfc1508d (kx 2023-03-24 03:55:33 +0300  349)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  350)     xmlFree( content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  351) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  352)     commit = xml_find_node_by_name( entry, "commit" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  353)     if( !commit )
bfc1508d (kx 2023-03-24 03:55:33 +0300  354)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  355)       xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  356)       xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  357)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  358)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  359)     content = xmlGetProp( commit, (const unsigned char *)"revision");
bfc1508d (kx 2023-03-24 03:55:33 +0300  360)     if( !content )
bfc1508d (kx 2023-03-24 03:55:33 +0300  361)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  362)       xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  363)       xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  364)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  365)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  366)     info->revision = atoi( (const char *)content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  367)     xmlFree( content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  368) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  369)     for( cnode = commit->children; cnode; cnode = cnode->next )
bfc1508d (kx 2023-03-24 03:55:33 +0300  370)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  371)       if( cnode->type == XML_ELEMENT_NODE )
bfc1508d (kx 2023-03-24 03:55:33 +0300  372)       {
bfc1508d (kx 2023-03-24 03:55:33 +0300  373)         if( !strcmp( "author", (char *)cnode->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  374)         {
bfc1508d (kx 2023-03-24 03:55:33 +0300  375)           content = xmlNodeGetContent( cnode );
bfc1508d (kx 2023-03-24 03:55:33 +0300  376)           if( !content ) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300  377)           {
bfc1508d (kx 2023-03-24 03:55:33 +0300  378)             int   len = (int)strlen( (const char *)content ) + 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  379)             char *author = (char *)__sbrk( len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  380)             memcpy( (void *)author, (const void *)content, len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  381)             info->author = (const char *)author;
bfc1508d (kx 2023-03-24 03:55:33 +0300  382)           }
bfc1508d (kx 2023-03-24 03:55:33 +0300  383)           xmlFree( content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  384)         }
bfc1508d (kx 2023-03-24 03:55:33 +0300  385)         if( !strcmp( "date", (char *)cnode->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  386)         {
bfc1508d (kx 2023-03-24 03:55:33 +0300  387)           content = xmlNodeGetContent( cnode );
bfc1508d (kx 2023-03-24 03:55:33 +0300  388)           if( !content ) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300  389)           {
bfc1508d (kx 2023-03-24 03:55:33 +0300  390)             struct tm tm;
bfc1508d (kx 2023-03-24 03:55:33 +0300  391)             time_t    time = -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  392) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  393)             time = parse_date( &tm, (const char *)content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  394)             info->date = time;
bfc1508d (kx 2023-03-24 03:55:33 +0300  395)           }
bfc1508d (kx 2023-03-24 03:55:33 +0300  396)           xmlFree( content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  397)         }
bfc1508d (kx 2023-03-24 03:55:33 +0300  398)       }
bfc1508d (kx 2023-03-24 03:55:33 +0300  399)     } /* End for( cnode = commit->children; cnode; cnode = cnode->next ) */
bfc1508d (kx 2023-03-24 03:55:33 +0300  400)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  401) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  402)   xmlFreeDoc(doc);
bfc1508d (kx 2023-03-24 03:55:33 +0300  403)   xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  404) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  405) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  406) void csvn_repo_info( struct csvn_info *info, int revision )
bfc1508d (kx 2023-03-24 03:55:33 +0300  407) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  408)   const char *co_prefix = ctx.repo.checkout_ro_prefix;
c7693c71 (kx 2023-04-12 19:21:06 +0300  409)   const char *name      = ctx.repo.name;
c7693c71 (kx 2023-04-12 19:21:06 +0300  410)   const char *repo_root = ctx.repo.repo_root;
bfc1508d (kx 2023-03-24 03:55:33 +0300  411) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  412)   if( co_prefix )
bfc1508d (kx 2023-03-24 03:55:33 +0300  413)   {
c7693c71 (kx 2023-04-12 19:21:06 +0300  414)     char repo_path[PATH_MAX] = { 0 };
c7693c71 (kx 2023-04-12 19:21:06 +0300  415)     char cmd[PATH_MAX];
bfc1508d (kx 2023-03-24 03:55:33 +0300  416)     struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  417)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  418)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  419) 
c7693c71 (kx 2023-04-12 19:21:06 +0300  420)     if( repo_root && *repo_root )
c7693c71 (kx 2023-04-12 19:21:06 +0300  421)     {
c7693c71 (kx 2023-04-12 19:21:06 +0300  422)       strcat( (char *)&repo_path[0], repo_root );
c7693c71 (kx 2023-04-12 19:21:06 +0300  423)       strcat( (char *)&repo_path[0], "/" );
c7693c71 (kx 2023-04-12 19:21:06 +0300  424)     }
c7693c71 (kx 2023-04-12 19:21:06 +0300  425)     strcat( (char *)&repo_path[0], name );
c7693c71 (kx 2023-04-12 19:21:06 +0300  426) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  427)     if( revision )
bfc1508d (kx 2023-03-24 03:55:33 +0300  428)       snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  429)                 "svn info --revision %d --xml %s/%s/ 2>/dev/null",
c7693c71 (kx 2023-04-12 19:21:06 +0300  430)                 revision, co_prefix, (char *)&repo_path[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  431)     else
bfc1508d (kx 2023-03-24 03:55:33 +0300  432)       snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  433)                 "svn info --xml %s/%s/ 2>/dev/null",
c7693c71 (kx 2023-04-12 19:21:06 +0300  434)                 co_prefix, (char *)&repo_path[0] );
bfc1508d (kx 2023-03-24 03:55:33 +0300  435)     p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  436)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  437)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  438)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  439)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  440)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  441)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  442) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  443)     xml_csvn_info( &buf, info );
bfc1508d (kx 2023-03-24 03:55:33 +0300  444)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  445)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  446)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  447) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  448) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  449) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  450) static const char *lang_info_by_path( const char *path )
bfc1508d (kx 2023-03-24 03:55:33 +0300  451) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  452)   char *lang = NULL, *name = NULL, *ext = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  453) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  454)   if( !path || !*path ) return (const char *)lang;
bfc1508d (kx 2023-03-24 03:55:33 +0300  455) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  456)   ext = rindex( path, '.' );
bfc1508d (kx 2023-03-24 03:55:33 +0300  457)   if( ext )
bfc1508d (kx 2023-03-24 03:55:33 +0300  458)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  459)     if( !strncasecmp( ext, ".mk", 3 )       ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  460)         !strncasecmp( ext, ".make", 5 )     ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  461)         !strncasecmp( ext, ".Makefile", 9 )   )
bfc1508d (kx 2023-03-24 03:55:33 +0300  462)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  463)       lang = (char *)__sbrk( 9 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  464)       sprintf( lang, "Makefile" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  465)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  466)     else if( !strncasecmp( ext, ".md", 3 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  467)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  468)       lang = (char *)__sbrk( 9 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  469)       sprintf( lang, "Markdown" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  470)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  471)     else if( !strncasecmp( ext, ".diff", 5 ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  472)              !strncasecmp( ext, ".patch", 6 )  )
bfc1508d (kx 2023-03-24 03:55:33 +0300  473)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  474)       lang = (char *)__sbrk( 9 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  475)       sprintf( lang, "Diff" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  476)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  477)     else if( !strncasecmp( ext, ".c", 2 ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  478)              !strncasecmp( ext, ".h", 2 )   )
bfc1508d (kx 2023-03-24 03:55:33 +0300  479)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  480)       lang = (char *)__sbrk( 2 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  481)       sprintf( lang, "C" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  482)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  483)     else if( !strncasecmp( ext, ".cpp", 4 ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  484)              !strncasecmp( ext, ".cxx", 4 ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  485)              !strncasecmp( ext, ".hpp", 4 )   )
bfc1508d (kx 2023-03-24 03:55:33 +0300  486)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  487)       lang = (char *)__sbrk( 4 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  488)       sprintf( lang, "C++" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  489)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  490)     else if( !strncasecmp( ext, ".html", 5 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  491)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  492)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  493)       sprintf( lang, "HTML" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  494)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  495)     else if( !strncasecmp( ext, ".css", 4 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  496)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  497)       lang = (char *)__sbrk( 4 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  498)       sprintf( lang, "CSS" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  499)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  500)     else if( !strncasecmp( ext, ".js", 3 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  501)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  502)       lang = (char *)__sbrk( 11 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  503)       sprintf( lang, "javascript" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  504)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  505)     else if( !strncasecmp( ext, ".json", 5 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  506)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  507)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  508)       sprintf( lang, "JSON" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  509)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  510)     else if( !strncasecmp( ext, ".less", 5 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  511)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  512)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  513)       sprintf( lang, "LESS" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  514)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  515)     else if( !strncasecmp( ext, ".scss", 5 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  516)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  517)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  518)       sprintf( lang, "SCSS" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  519)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  520)     else if( !strncasecmp( ext, ".pl", 3 ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300  521)              !strncasecmp( ext, ".pm", 3 )   )
bfc1508d (kx 2023-03-24 03:55:33 +0300  522)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  523)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  524)       sprintf( lang, "Perl" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  525)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  526)     else if( !strncasecmp( ext, ".py", 3 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  527)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  528)       lang = (char *)__sbrk( 7 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  529)       sprintf( lang, "Python" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  530)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  531)     else if( !strncasecmp( ext, ".php", 4 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  532)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  533)       lang = (char *)__sbrk( 4 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  534)       sprintf( lang, "PHP" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  535)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  536)     else if( !strncasecmp( ext, ".txt", 4 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  537)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  538)       lang = (char *)__sbrk( 10 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  539)       sprintf( lang, "plaintext" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  540)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  541)     else if( !strncasecmp( ext, ".go", 3 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  542)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  543)       lang = (char *)__sbrk( 3 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  544)       sprintf( lang, "Go" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  545)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  546)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  547) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  548)   name = rindex( path, '/' );
bfc1508d (kx 2023-03-24 03:55:33 +0300  549)   if( name )
bfc1508d (kx 2023-03-24 03:55:33 +0300  550)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  551)     ++name;
bfc1508d (kx 2023-03-24 03:55:33 +0300  552)     if( !strncasecmp( name, "Makefile", 8 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  553)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  554)       lang = (char *)__sbrk( 9 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  555)       sprintf( lang, "Makefile" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  556)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  557)     else if( !strcasecmp( name, "README" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  558)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  559)       lang = (char *)__sbrk( 10 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  560)       sprintf( lang, "Plaintext" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  561)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  562)     else if( !strcasecmp( name, "LICENSE" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  563)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  564)       lang = (char *)__sbrk( 10 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  565)       sprintf( lang, "Plaintext" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  566)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  567)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  568) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  569)   /***************************
bfc1508d (kx 2023-03-24 03:55:33 +0300  570)     all chances are exhausted. probably highlight.js do it correctly...
bfc1508d (kx 2023-03-24 03:55:33 +0300  571)    */
bfc1508d (kx 2023-03-24 03:55:33 +0300  572)   /*
bfc1508d (kx 2023-03-24 03:55:33 +0300  573)   if( !lang )
bfc1508d (kx 2023-03-24 03:55:33 +0300  574)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  575)     lang = (char *)__sbrk( 10 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  576)     sprintf( lang, "plaintext" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  577)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  578)   */
bfc1508d (kx 2023-03-24 03:55:33 +0300  579) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  580)   return (const char *)lang;
bfc1508d (kx 2023-03-24 03:55:33 +0300  581) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  582) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  583) static const char *lang_info( const char *mime_type, const char *path )
bfc1508d (kx 2023-03-24 03:55:33 +0300  584) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  585)   char *lang = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  586) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  587)   if( !mime_type ) return (const char *)lang;
bfc1508d (kx 2023-03-24 03:55:33 +0300  588) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  589)   if( !strncmp( mime_type, "text/", 5 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  590)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  591)     if( !strncmp( mime_type, "text/x-c", 8 ) || !strncmp( mime_type, "text/x-csrc", 11 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  592)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  593)       lang = (char *)__sbrk( 2 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  594)       sprintf( lang, "C" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  595)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  596)     else if( !strncmp( mime_type, "text/x-diff", 11 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  597)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  598)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  599)       sprintf( lang, "Diff" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  600)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  601)     else if( !strncmp( mime_type, "text/x-makefile", 15 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  602)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  603)       lang = (char *)__sbrk( 9 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  604)       sprintf( lang, "Makefile" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  605)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  606)     else if( !strncmp( mime_type, "text/x-shell", 12 ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  607)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  608)       lang = (char *)__sbrk( 5 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  609)       sprintf( lang, "Bash" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  610)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  611) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  612)     /*
bfc1508d (kx 2023-03-24 03:55:33 +0300  613)       The 'text/plain;' mime type does not mean that the file contains plain text.
bfc1508d (kx 2023-03-24 03:55:33 +0300  614)       But we have to identify the language:
bfc1508d (kx 2023-03-24 03:55:33 +0300  615)      */
bfc1508d (kx 2023-03-24 03:55:33 +0300  616)     if( !lang && path )
bfc1508d (kx 2023-03-24 03:55:33 +0300  617)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  618)       /* Here we can make lang identification by filename or extension */
bfc1508d (kx 2023-03-24 03:55:33 +0300  619)       lang = (char *)lang_info_by_path( path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  620)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  621)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  622) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  623)   return (const char *)lang;
bfc1508d (kx 2023-03-24 03:55:33 +0300  624) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  625) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  626) static const char *mime_info( struct csvn_info *info, const char *buffer, size_t length )
bfc1508d (kx 2023-03-24 03:55:33 +0300  627) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  628)   const char *mime = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  629)   magic_t     magic;
bfc1508d (kx 2023-03-24 03:55:33 +0300  630) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  631)   if( !info || !buffer || !length ) return mime;
bfc1508d (kx 2023-03-24 03:55:33 +0300  632) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  633)   magic = magic_open( MAGIC_MIME );
bfc1508d (kx 2023-03-24 03:55:33 +0300  634)   if( !magic )
bfc1508d (kx 2023-03-24 03:55:33 +0300  635)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  636)     html_fatal( "unable to initialize magic library" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  637)     return mime;
bfc1508d (kx 2023-03-24 03:55:33 +0300  638)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  639)   if( magic_load( magic, NULL ) != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  640)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  641)     html_fatal( "cannot load magic database - %s\n", magic_error( magic ) );
bfc1508d (kx 2023-03-24 03:55:33 +0300  642)     magic_close( magic );
bfc1508d (kx 2023-03-24 03:55:33 +0300  643)     return mime;
bfc1508d (kx 2023-03-24 03:55:33 +0300  644)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  645) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  646)   mime = magic_buffer( magic, buffer, length );
bfc1508d (kx 2023-03-24 03:55:33 +0300  647)   if( mime )
bfc1508d (kx 2023-03-24 03:55:33 +0300  648)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  649)     int len = (int)strlen( mime ) + 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  650)     char *mime_type = (char *)__sbrk( len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  651)     memcpy( (void *)mime_type, (const void *)mime, len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  652)     info->mime = (const char *)mime_type;
bfc1508d (kx 2023-03-24 03:55:33 +0300  653)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  654) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  655)   magic_close( magic );
bfc1508d (kx 2023-03-24 03:55:33 +0300  656)   return mime;
bfc1508d (kx 2023-03-24 03:55:33 +0300  657) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  658) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  659) void csvn_rpath_mime_info( struct csvn_info *info, const char *relative_path, int revision )
bfc1508d (kx 2023-03-24 03:55:33 +0300  660) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  661)   const char *co_prefix = ctx.repo.checkout_ro_prefix;
c7693c71 (kx 2023-04-12 19:21:06 +0300  662)   const char *name      = ctx.repo.name;
c7693c71 (kx 2023-04-12 19:21:06 +0300  663)   const char *repo_root = ctx.repo.repo_root;
bfc1508d (kx 2023-03-24 03:55:33 +0300  664) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  665)   if( !info || !relative_path ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  666) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  667)   if( co_prefix )
bfc1508d (kx 2023-03-24 03:55:33 +0300  668)   {
c7693c71 (kx 2023-04-12 19:21:06 +0300  669)     char repo_path[PATH_MAX] = { 0 };
c7693c71 (kx 2023-04-12 19:21:06 +0300  670)     char cmd[PATH_MAX];
bfc1508d (kx 2023-03-24 03:55:33 +0300  671)     struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  672)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  673)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  674) 
c7693c71 (kx 2023-04-12 19:21:06 +0300  675)     if( repo_root && *repo_root )
c7693c71 (kx 2023-04-12 19:21:06 +0300  676)     {
c7693c71 (kx 2023-04-12 19:21:06 +0300  677)       strcat( (char *)&repo_path[0], repo_root );
c7693c71 (kx 2023-04-12 19:21:06 +0300  678)       strcat( (char *)&repo_path[0], "/" );
c7693c71 (kx 2023-04-12 19:21:06 +0300  679)     }
c7693c71 (kx 2023-04-12 19:21:06 +0300  680)     strcat( (char *)&repo_path[0], name );
c7693c71 (kx 2023-04-12 19:21:06 +0300  681) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  682)     if( revision )
bfc1508d (kx 2023-03-24 03:55:33 +0300  683)       snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  684)                 "svn cat --revision %d %s/%s/%s 2>/dev/null | tr -d '\\0' | head -c 1024",
c7693c71 (kx 2023-04-12 19:21:06 +0300  685)                 revision, co_prefix, (char *)&repo_path[0], relative_path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  686)     else
bfc1508d (kx 2023-03-24 03:55:33 +0300  687)       snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  688)                 "svn cat %s/%s/%s 2>/dev/null | tr -d '\\0' | head -c 1024",
c7693c71 (kx 2023-04-12 19:21:06 +0300  689)                 co_prefix, (char *)&repo_path[0], relative_path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  690)     p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  691)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  692)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  693)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  694)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  695)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  696)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  697)     if( buf.buf[0] )
bfc1508d (kx 2023-03-24 03:55:33 +0300  698)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  699)       mime_info( info, (const char *)buf.buf, buf.len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  700)       info->lang = lang_info( (const char *)(info->mime), relative_path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  701)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  702)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  703)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  704)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  705) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  706) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  707) void csvn_rpath_info( struct csvn_info *info, const char *relative_path, int revision )
bfc1508d (kx 2023-03-24 03:55:33 +0300  708) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  709)   const char *co_prefix = ctx.repo.checkout_ro_prefix;
c7693c71 (kx 2023-04-12 19:21:06 +0300  710)   const char *name      = ctx.repo.name;
c7693c71 (kx 2023-04-12 19:21:06 +0300  711)   const char *repo_root = ctx.repo.repo_root;
bfc1508d (kx 2023-03-24 03:55:33 +0300  712) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  713)   if( !info || !relative_path ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  714) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  715)   if( co_prefix )
bfc1508d (kx 2023-03-24 03:55:33 +0300  716)   {
c7693c71 (kx 2023-04-12 19:21:06 +0300  717)     char repo_path[PATH_MAX] = { 0 };
c7693c71 (kx 2023-04-12 19:21:06 +0300  718)     char cmd[PATH_MAX];
bfc1508d (kx 2023-03-24 03:55:33 +0300  719)     struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  720)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  721)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  722) 
c7693c71 (kx 2023-04-12 19:21:06 +0300  723)     if( repo_root && *repo_root )
c7693c71 (kx 2023-04-12 19:21:06 +0300  724)     {
c7693c71 (kx 2023-04-12 19:21:06 +0300  725)       strcat( (char *)&repo_path[0], repo_root );
c7693c71 (kx 2023-04-12 19:21:06 +0300  726)       strcat( (char *)&repo_path[0], "/" );
c7693c71 (kx 2023-04-12 19:21:06 +0300  727)     }
c7693c71 (kx 2023-04-12 19:21:06 +0300  728)     strcat( (char *)&repo_path[0], name );
c7693c71 (kx 2023-04-12 19:21:06 +0300  729) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  730)     if( revision )
bfc1508d (kx 2023-03-24 03:55:33 +0300  731)       snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  732)                 "svn info --revision %d --xml %s/%s/%s 2>/dev/null",
c7693c71 (kx 2023-04-12 19:21:06 +0300  733)                 revision, co_prefix, (char *)&repo_path[0], relative_path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  734)     else
bfc1508d (kx 2023-03-24 03:55:33 +0300  735)       snprintf( (char *)&cmd[0], 1024,
bfc1508d (kx 2023-03-24 03:55:33 +0300  736)                 "svn info --xml %s/%s/%s 2>/dev/null",
c7693c71 (kx 2023-04-12 19:21:06 +0300  737)                 co_prefix, (char *)&repo_path[0], relative_path );
bfc1508d (kx 2023-03-24 03:55:33 +0300  738)     p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  739)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  740)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  741)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  742)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  743)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  744)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  745) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  746)     xml_csvn_info( &buf, info );
bfc1508d (kx 2023-03-24 03:55:33 +0300  747)     if( info->kind == KIND_FILE )
bfc1508d (kx 2023-03-24 03:55:33 +0300  748)       csvn_rpath_mime_info( info, relative_path, revision );
bfc1508d (kx 2023-03-24 03:55:33 +0300  749)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  750)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  751)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  752) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  753) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  754) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  755) static int xml_csvn_dirs_number( const struct strbuf *buf )
bfc1508d (kx 2023-03-24 03:55:33 +0300  756) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  757)   xmlDocPtr doc = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  758)   xmlNode *root = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  759)   int count     = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  760) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  761)   LIBXML_TEST_VERSION
bfc1508d (kx 2023-03-24 03:55:33 +0300  762) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  763)   doc = xmlReadMemory( buf->buf, buf->len, "list.xml", NULL, 0 );
bfc1508d (kx 2023-03-24 03:55:33 +0300  764)   if( !doc )
bfc1508d (kx 2023-03-24 03:55:33 +0300  765)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  766)     html_fatal( "cannot parse svn list.xml" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  767)     return count;
bfc1508d (kx 2023-03-24 03:55:33 +0300  768)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  769) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  770)   root = xmlDocGetRootElement( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  771)   if( !root )
bfc1508d (kx 2023-03-24 03:55:33 +0300  772)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  773)     xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  774)     xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  775)     return count;
bfc1508d (kx 2023-03-24 03:55:33 +0300  776)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  777) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  778)   if( !strcmp( "lists", (char *)root->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  779)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  780)     xmlNode *list = NULL, *node = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  781) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  782)     list = xml_find_node_by_name( root, "list" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  783)     if( !list )
bfc1508d (kx 2023-03-24 03:55:33 +0300  784)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  785)       xmlFreeDoc( doc );
bfc1508d (kx 2023-03-24 03:55:33 +0300  786)       xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  787)       return count;
bfc1508d (kx 2023-03-24 03:55:33 +0300  788)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  789) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  790)     /************************************************
bfc1508d (kx 2023-03-24 03:55:33 +0300  791)       Count directories (excluding 'deadwood' name):
bfc1508d (kx 2023-03-24 03:55:33 +0300  792)      */
bfc1508d (kx 2023-03-24 03:55:33 +0300  793)     for( node = list->children; node; node = node->next )
bfc1508d (kx 2023-03-24 03:55:33 +0300  794)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  795)       if( node->type == XML_ELEMENT_NODE && !strcmp( "entry", (char *)node->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  796)       {
bfc1508d (kx 2023-03-24 03:55:33 +0300  797)         xmlChar *content = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  798)         xmlNode *param   = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  799) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  800)         content = xmlGetProp( node, (const unsigned char *)"kind" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  801)         if( !strcmp( (const char *)content, "dir" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  802)         {
bfc1508d (kx 2023-03-24 03:55:33 +0300  803)           xmlChar *name = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  804) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  805)           for( param = node->children; param; param= param->next )
bfc1508d (kx 2023-03-24 03:55:33 +0300  806)           {
bfc1508d (kx 2023-03-24 03:55:33 +0300  807)             if( param->type == XML_ELEMENT_NODE && !strcmp( "name", (char *)param->name ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  808)             {
bfc1508d (kx 2023-03-24 03:55:33 +0300  809)               name = xmlNodeGetContent( param );
bfc1508d (kx 2023-03-24 03:55:33 +0300  810)             }
bfc1508d (kx 2023-03-24 03:55:33 +0300  811)           }
bfc1508d (kx 2023-03-24 03:55:33 +0300  812) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  813)           if( name && strcmp( (char *)name, "deadwood" ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300  814)           {
bfc1508d (kx 2023-03-24 03:55:33 +0300  815)             count += 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  816)           }
bfc1508d (kx 2023-03-24 03:55:33 +0300  817) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  818)           if( name )
bfc1508d (kx 2023-03-24 03:55:33 +0300  819)             xmlFree( name );
bfc1508d (kx 2023-03-24 03:55:33 +0300  820)         }
bfc1508d (kx 2023-03-24 03:55:33 +0300  821)         xmlFree( content );
bfc1508d (kx 2023-03-24 03:55:33 +0300  822)       }
bfc1508d (kx 2023-03-24 03:55:33 +0300  823)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  824)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  825) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  826)   xmlFreeDoc(doc);
bfc1508d (kx 2023-03-24 03:55:33 +0300  827)   xmlCleanupParser();
bfc1508d (kx 2023-03-24 03:55:33 +0300  828) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  829)   return count;
bfc1508d (kx 2023-03-24 03:55:33 +0300  830) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  831) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  832) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  833) void csvn_repo_branches_number( struct csvn_repository *rctx )
bfc1508d (kx 2023-03-24 03:55:33 +0300  834) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  835)   const char *prefix = NULL, *name = NULL, *branches = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  836) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  837)   if( !rctx ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  838) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  839)   name     = rctx->name;
bfc1508d (kx 2023-03-24 03:55:33 +0300  840)   branches = rctx->branches;
bfc1508d (kx 2023-03-24 03:55:33 +0300  841)   prefix   = rctx->checkout_ro_prefix;
bfc1508d (kx 2023-03-24 03:55:33 +0300  842) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  843)   if( prefix && name && branches )
bfc1508d (kx 2023-03-24 03:55:33 +0300  844)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  845)     char cmd[1024];
bfc1508d (kx 2023-03-24 03:55:33 +0300  846)     struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  847)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  848)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  849) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  850)     snprintf( (char *)&cmd[0], 1024, "svn list --xml %s/%s/%s 2>/dev/null", prefix, name, branches );
bfc1508d (kx 2023-03-24 03:55:33 +0300  851)     p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  852)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  853)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  854)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  855)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  856)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  857)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  858) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  859)     rctx->nbranches = xml_csvn_dirs_number( (const struct strbuf *)&buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  860) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  861)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  862)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  863)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  864) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  865) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  866) void csvn_repo_tags_number( struct csvn_repository *rctx )
bfc1508d (kx 2023-03-24 03:55:33 +0300  867) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  868)   const char *prefix = NULL, *name = NULL, *tags = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  869) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  870)   if( !rctx ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  871) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  872)   name   = rctx->name;
bfc1508d (kx 2023-03-24 03:55:33 +0300  873)   tags   = rctx->tags;
bfc1508d (kx 2023-03-24 03:55:33 +0300  874)   prefix = rctx->checkout_ro_prefix;
bfc1508d (kx 2023-03-24 03:55:33 +0300  875) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  876)   if( prefix && name && tags )
bfc1508d (kx 2023-03-24 03:55:33 +0300  877)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  878)     char cmd[1024];
bfc1508d (kx 2023-03-24 03:55:33 +0300  879)     struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  880)     pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  881)     int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  882) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  883)     snprintf( (char *)&cmd[0], 1024, "svn list --xml %s/%s/%s 2>/dev/null", prefix, name, tags );
bfc1508d (kx 2023-03-24 03:55:33 +0300  884)     p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  885)     rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  886)     if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  887)     {
bfc1508d (kx 2023-03-24 03:55:33 +0300  888)       strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  889)       return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  890)     }
bfc1508d (kx 2023-03-24 03:55:33 +0300  891) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  892)     rctx->ntags = xml_csvn_dirs_number( (const struct strbuf *)&buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  893) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  894)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  895)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  896)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  897) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  898) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  899) void csvn_svn_version( struct csvn_versions *vctx )
bfc1508d (kx 2023-03-24 03:55:33 +0300  900) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  901)   char cmd[1024];
bfc1508d (kx 2023-03-24 03:55:33 +0300  902)   struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  903)   pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  904)   int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  905) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  906)   char *version = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  907)   int   len = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  908) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  909)   if( !vctx ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  910) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  911)   snprintf( (char *)&cmd[0], 1024, "svn --version --quiet 2>/dev/null" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  912)   p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  913)   rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  914)   if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  915)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  916)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  917)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  918)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  919) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  920)   strbuf_trim( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  921) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  922)   len = (int)strlen( buf.buf ) + 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  923)   version = (char *)__sbrk( len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  924)   memcpy( (void *)version, (const void *)buf.buf, (size_t)len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  925)   vctx->subversion = (const char *)version;
bfc1508d (kx 2023-03-24 03:55:33 +0300  926) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  927)   strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  928) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  929)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  930) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  931) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  932) void csvn_nginx_version( struct csvn_versions *vctx )
bfc1508d (kx 2023-03-24 03:55:33 +0300  933) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  934)   char cmd[1024];
bfc1508d (kx 2023-03-24 03:55:33 +0300  935)   struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  936)   pid_t p = (pid_t) -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  937)   int   rc;
bfc1508d (kx 2023-03-24 03:55:33 +0300  938) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  939)   char *version = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300  940)   int   len = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300  941) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  942)   if( !vctx ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  943) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  944)   snprintf( (char *)&cmd[0], 1024, "nginx -v 2>&1 | cut -f2 -d'/'" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  945)   p = sys_exec_command( &buf, cmd );
bfc1508d (kx 2023-03-24 03:55:33 +0300  946)   rc = sys_wait_command( p, NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300  947)   if( rc != 0 )
bfc1508d (kx 2023-03-24 03:55:33 +0300  948)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  949)     strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  950)     return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  951)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  952) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  953)   if( buf.buf[0] )
bfc1508d (kx 2023-03-24 03:55:33 +0300  954)   {
bfc1508d (kx 2023-03-24 03:55:33 +0300  955)     strbuf_trim( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  956) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  957)     len = (int)strlen( buf.buf ) + 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300  958)     version = (char *)__sbrk( len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  959)     memcpy( (void *)version, (const void *)buf.buf, (size_t)len );
bfc1508d (kx 2023-03-24 03:55:33 +0300  960)     vctx->nginx = (const char *)version;
bfc1508d (kx 2023-03-24 03:55:33 +0300  961)   }
bfc1508d (kx 2023-03-24 03:55:33 +0300  962) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  963)   strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  964) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  965)   return;
bfc1508d (kx 2023-03-24 03:55:33 +0300  966) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  967) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  968) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  969) void csvn_print_404_page( void )
bfc1508d (kx 2023-03-24 03:55:33 +0300  970) {
bfc1508d (kx 2023-03-24 03:55:33 +0300  971)   FILE  *fp;
bfc1508d (kx 2023-03-24 03:55:33 +0300  972)   struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300  973) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  974)   fp = xfopen( ctx.page.header, "r" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  975)   (void)strbuf_env_fread( &buf, fp );
bfc1508d (kx 2023-03-24 03:55:33 +0300  976)   fclose( fp );
bfc1508d (kx 2023-03-24 03:55:33 +0300  977) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  978)   strbuf_addf( &buf, "        <div class=\"content segment\">\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  979)   strbuf_addf( &buf, "          <div class=\"container\">\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  980)   strbuf_addf( &buf, "            <div class=\"csvn-main-content\">\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  981)   strbuf_addf( &buf, "              <h1>Requested resource not found</h1>\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  982)   strbuf_addf( &buf, "              <p class='leading'>Please check the requested URL or try again later.</p>\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  983)   strbuf_addf( &buf, "            </div> <!-- End of csvn-main-content -->\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  984)   strbuf_addf( &buf, "          </div> <!-- End of container -->\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  985)   strbuf_addf( &buf, "        </div> <!-- End of content segment -->\n" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  986) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  987)   fp = xfopen( ctx.page.footer, "r" );
bfc1508d (kx 2023-03-24 03:55:33 +0300  988)   (void)strbuf_env_fread( &buf, fp );
bfc1508d (kx 2023-03-24 03:55:33 +0300  989)   fclose( fp );
bfc1508d (kx 2023-03-24 03:55:33 +0300  990) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  991)   ctx.page.size = buf.len;
bfc1508d (kx 2023-03-24 03:55:33 +0300  992)   csvn_print_http_headers();
bfc1508d (kx 2023-03-24 03:55:33 +0300  993)   strbuf_write( &buf, STDOUT_FILENO );
bfc1508d (kx 2023-03-24 03:55:33 +0300  994)   strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300  995) }
bfc1508d (kx 2023-03-24 03:55:33 +0300  996) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  997) 
bfc1508d (kx 2023-03-24 03:55:33 +0300  998) void csvn_print_raw_file( struct strbuf *sb, const char *mime )
bfc1508d (kx 2023-03-24 03:55:33 +0300  999) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 1000)   struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300 1001)   char *p = (char *)mime;
bfc1508d (kx 2023-03-24 03:55:33 +0300 1002) 
bfc1508d (kx 2023-03-24 03:55:33 +0300 1003)   char *http_format = "Date: %s\n"
bfc1508d (kx 2023-03-24 03:55:33 +0300 1004)                       "Content-Type: %s\n"
bfc1508d (kx 2023-03-24 03:55:33 +0300 1005)                       "Content-Length: %ld\n\n";
bfc1508d (kx 2023-03-24 03:55:33 +0300 1006) 
bfc1508d (kx 2023-03-24 03:55:33 +0300 1007)   if( !sb || !mime ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 1008) 
bfc1508d (kx 2023-03-24 03:55:33 +0300 1009)   while( *p && *p != ';' ) ++p;
bfc1508d (kx 2023-03-24 03:55:33 +0300 1010)   if( *p ) *p = '\0';
bfc1508d (kx 2023-03-24 03:55:33 +0300 1011) 
bfc1508d (kx 2023-03-24 03:55:33 +0300 1012)   strbuf_addf( &buf, http_format, http_date( time(NULL) ), mime, sb->len );
bfc1508d (kx 2023-03-24 03:55:33 +0300 1013)   strbuf_addbuf( &buf, (const struct strbuf *)sb );
bfc1508d (kx 2023-03-24 03:55:33 +0300 1014)   strbuf_write( &buf, STDOUT_FILENO );
bfc1508d (kx 2023-03-24 03:55:33 +0300 1015)   strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300 1016) 
bfc1508d (kx 2023-03-24 03:55:33 +0300 1017)   exit( 0 );
bfc1508d (kx 2023-03-24 03:55:33 +0300 1018) }