getURL($rep, $pathSoFar, 'dir').$passRevString;
$vars['pathlinks'] = '(root)/';
for ($n = 1; $n < $limit; $n++) {
$pathSoFar .= html_entity_decode($pathComponents[$n]).'/';
$pathSoFarURL = $config->getURL($rep, $pathSoFar, 'dir').$passRevString;
$vars['pathlinks'] .= ''.$pathComponents[$n].'/';
}
if (!empty($pathComponents[$n])) {
$pegrev = ($peg && $peg != $rev) ? ' @ '.$peg.'' : '';
if ($dir) {
$vars['pathlinks'] .= ''.$pathComponents[$n].'/'.$pegrev.'';
} else {
$vars['pathlinks'] .= ''.$pathComponents[$n].$pegrev.'';
}
}
}
// }}}
function createRevAndPegString($rev, $peg) {
$params = array();
if ($rev) $params[] = 'rev='.$rev;
if ($peg) $params[] = 'peg='.$peg;
return implode('&', $params);
}
function createDifferentRevAndPegString($rev, $peg) {
$params = array();
if ($rev && (!$peg || $rev != $peg)) $params[] = 'rev='.$rev;
if ($peg) $params[] = 'peg='.$peg;
return implode('&', $params);
}
function anchorForPath($path) {
global $config;
// (X)HMTL id/name attribute must be this format: [A-Za-z][A-Za-z0-9-_.:]*
// MD5 hashes are 32 characters, deterministic, quite collision-resistant,
// and work for any string, regardless of encoding or special characters.
if ($config->treeView)
return 'a'.md5($path);
else
return '';
}
// {{{ create_anchors
//
// Create links out of http:// and mailto: tags
// TODO: the target="_blank" nonsense should be optional (or specified by the template)
function create_anchors($text) {
$ret = $text;
// Match correctly formed URLs that aren't already links
$ret = preg_replace('#\b(?\\1://\\2\\3',
$ret);
// Now match anything beginning with www, as long as it's not //www since they were matched above
$ret = preg_replace('#\b(?www.\\1\\2',
$ret);
// Match email addresses
$ret = preg_replace('#\b([\w\-_.]+)@([\w\-.]+)\.(\w{2,})\b#i',
'\\1@\\2.\\3',
$ret);
return $ret;
}
// }}}
// {{{ getFullURL
function getFullURL($loc) {
$protocol = 'http';
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
$protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'];
} else if (isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) {
$protocol = 'https';
}
$port = ':'.$_SERVER['SERVER_PORT'];
if ((':80' == $port && 'http' == $protocol) || (':443' == $port && 'https' == $protocol)) {
$port = '';
}
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else if (isset($_SERVER['HTTP_HOST'])) {
$host = $_SERVER['HTTP_HOST'];
} else if (isset($_SERVER['SERVER_NAME'])) {
$host = $_SERVER['SERVER_NAME'].$port;
} else if (isset($_SERVER['SERVER_ADDR'])) {
$host = $_SERVER['SERVER_ADDR'].$port;
} else {
print 'Unable to redirect';
exit;
}
// make sure we have a directory to go to
if (empty($loc)) {
$loc = '/';
} else if ($loc{0} != '/') {
$loc = '/'.$loc;
}
$url = $protocol . '://' . $host . $loc;
return $url;
}
// }}}
function xml_entities($str) {
$entities = array();
$entities['&'] = '&';
$entities['<'] = '<';
$entities['>'] = '>';
$entities['"'] = '"';
$entities['\''] = ''';
return str_replace(array_keys($entities), array_values($entities), $str);
}
// {{{ hardspace
//
// Replace the spaces at the front of a line with hard spaces
// XXX: this is an unnecessary function; you can prevent whitespace from being
// trimmed via CSS (use the "white-space: pre;" properties). ~J
// in the meantime, here's an improved function (does nothing)
function hardspace($s) {
return '' . expandTabs($s) . '
';
}
// }}}
function wrapInCodeTagIfNecessary($string) {
global $config;
return ($config->getUseGeshi()) ? $string : ''.$string.'
';
}
// {{{ expandTabs
/**
* Expands the tabs in a line that may or may not include HTML.
*
* Enscript generates code with HTML, so we need to take that into account.
*
* @param string $s Line of possibly HTML-encoded text to expand
* @param int $tabwidth Tab width, -1 to use repository's default, 0 to collapse
* all tabs.
* @return string The expanded line.
* @since 2.1
*/
function expandTabs($s, $tabwidth = - 1) {
global $rep;
if ($tabwidth == -1) {
$tabwidth = $rep->getExpandTabsBy();
}
$pos = 0;
// Parse the string into chunks that are either 1 of: HTML tag, tab char, run of any other stuff
$chunks = preg_split('/((?:<.+?>)|(?:&.+?;)|(?:\t))/', $s, -1, PREG_SPLIT_DELIM_CAPTURE);
// Count the sizes of the chunks and replace tabs as we go
$chunkscount = count($chunks);
for ($i = 0; $i < $chunkscount; $i++) {
// make sure we're not dealing with an empty string
if (empty($chunks[$i])) continue;
switch ($chunks[$i]{0}) {
case '<': // HTML tag: ignore its width by doing nothing
break;
case '&': // HTML entity: count its width as 1 char
$pos++;
break;
case "\t": // Tab char: replace it with a run of spaces between length tabwidth and 1
$tabsize = $tabwidth - ($pos % $tabwidth);
$chunks[$i] = str_repeat(' ', $tabsize);
$pos += $tabsize;
break;
default: // Anything else: just keep track of its width
$pos += strlen($chunks[$i]);
break;
}
}
// Put the chunks back together and we've got the original line, detabbed.
return join('', $chunks);
}
// }}}
// {{{ datetimeFormatDuration
//
// Formats a duration of seconds for display.
//
// $seconds the number of seconds until something
// $nbsp true if spaces should be replaced by nbsp
// $skipSeconds true if seconds should be omitted
//
// return the formatted duration (e.g. @c "8h 6m 1s")
function datetimeFormatDuration($seconds, $nbsp = false, $skipSeconds = false) {
global $lang;
$neg = false;
if ($seconds < 0) {
$seconds = 0 - $seconds;
$neg = true;
}
$qty = array();
$names = array($lang['DAYLETTER'], $lang['HOURLETTER'], $lang['MINUTELETTER']);
$qty[] = (int)($seconds / (60 * 60 * 24));
$seconds %= 60 * 60 * 24;
$qty[] = (int)($seconds / (60 * 60));
$seconds %= 60 * 60;
$qty[] = (int)($seconds / 60);
if (!$skipSeconds) {
$qty[] = (int)($seconds % 60);
$names[] = $lang['SECONDLETTER'];
}
$text = $neg ? '-' : '';
$any = false;
$count = count($names);
$parts = 0;
for ($i = 0; $i < $count; $i++) {
// If a "higher valued" time slot had a value or this time slot
// has a value or this is the very last entry (i.e. all values
// are 0 and we still want to print seconds)
if ($any || $qty[$i] > 0 || $i == $count - 1) {
if ($any) $text .= $nbsp ? ' ' : ' ';
if ($any && $qty[$i] < 10) $text .= '0';
$text .= $qty[$i].$names[$i];
$any = true;
$parts++;
if ($parts >= 2) break;
}
}
return $text;
}
// }}}
function parseSvnTimestamp($dateString) {
// Try the simple approach of a built-in PHP function first.
$date = strtotime($dateString);
// If the resulting timestamp isn't sane, try parsing manually.
if ($date <= 0) {
$y = 0;
$mo = 0;
$d = 0;
$h = 0;
$m = 0;
$s = 0;
sscanf($dateString, '%d-%d-%dT%d:%d:%d.', $y, $mo, $d, $h, $m, $s);
$mo = substr('00'.$mo, -2);
$d = substr('00'.$d, -2);
$h = substr('00'.$h, -2);
$m = substr('00'.$m, -2);
$s = substr('00'.$s, -2);
$date = strtotime($y.'-'.$mo.'-'.$d.' '.$h.':'.$m.':'.$s.' GMT');
}
return $date;
}
// {{{ buildQuery
//
// Build parameters for url query part
function buildQuery($data, $separator = '&', $key = '') {
if (is_object($data))
$data = get_object_vars($data);
$p = array();
foreach ($data as $k => $v) {
$k = urlencode($k);
if (!empty($key))
$k = $key.'['.$k.']';
if (is_array($v) || is_object($v)) {
$p[] = buildQuery($v, $separator, $k);
} else {
$p[] = $k.'='.urlencode($v);
}
}
return implode($separator, $p);
}
// }}}
// {{{ getUserLanguage
function getUserLanguage($languages, $default, $userchoice) {
global $config;
if (!$config->useAcceptedLanguages()) return $default;
$acceptlangs = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : false;
if (!$acceptlangs)
return $default;
$langs = array();
$sublangs = array();
foreach (explode(',', $acceptlangs) as $str) {
$a = explode(';', $str, 2);
$lang = trim($a[0]);
$pos = strpos($lang, '-');
if ($pos !== false)
$sublangs[] = substr($lang, 0, $pos);
$q = 1.0;
if (count($a) == 2) {
$v = trim($a[1]);
if (substr($v, 0, 2) == 'q=')
$q = doubleval(substr($v, 2));
}
if ($userchoice)
$q *= 0.9;
$langs[$lang] = $q;
}
foreach ($sublangs as $l)
if (!isset($langs[$l]))
$langs[$l] = 0.1;
if ($userchoice)
$langs[$userchoice] = 1.0;
arsort($langs);
foreach ($langs as $code => $q) {
if (isset($languages[$code])) {
return $code;
}
}
return $default;
}
// }}}
function tempnamWithCheck($dir, $prefix) {
$tmp = tempnam($dir, $prefix);
if ($tmp == false) {
if (!headers_sent()) {
header('HTTP/1.x 500 Internal Server Error', true, 500);
error_log('Unable to create a temporary file. Either make the currently used folder ("' . $dir . '") writable for WebSVN or change the folder in the configuration.');
print 'Unable to create a temporary file. Either make the currently used folder writable for WebSVN or change the folder in the configuration.';
exit(0);
} else {
global $vars;
$vars['warning'] = 'Unable to create a temporary file. Either make the currently used folder writable for WebSVN or change the folder in the configuration.';
}
}
return $tmp;
}