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) }