scc-snap2html(1)
NAME
scc-snap2html - converts a SCC-snapshot to HTML-format
RELEASE
scc 1.23.185
SYNOPSIS
scc-snap2html [ -h|--help ] [ -s|--standalone ] <hostname>
DESCRIPTION
This program reads a SCC-snapshot from stdin and converts it to
HTML-format on stdout. The hierarchical classification in the snapshot
is converted to a hierarchical menu to the corresponding data. Refer to
scc(4) for a detailed description of a SCC-snapshot.
The resulting html-code only contains text and can be viewed with a
browser like lynx.
The snapshot contains DIV-tags with the following nested classes:
- SCC_SNAP
- SCC_SNAP_NAV
- SCC_SNAP_MENU
- SCC_SNAP_ENTRY
- SCC_SNAP_STATS
- SCC_SNAP_HELP
The sylesheet style.css in /var/opt/scc/data controls the markup.
OPTIONS
-h|--help Display the syntax and exit.
-s|--standalone Embed the stylesheet in the html-data and do not
show "external" links to logbook and index.html.
Use this option before transferring the html
version of the snapshot to a user.
ARGUMENTS
<name> name of the host to convert the SCC-snapshot for
DIAGNOSTICS
This program writes the following message to stderr:
Syntax error, use: scc-snap2html [ -h|--help ] [ -s|--standalone ] <name>
A syntax error was detected and reported.
scc-snap2html: insufficient permissions to write in data directory: <data_dir>
To run this program, log in as the owner of the directory.
RETURN VALUE
Upon completion, the program returns one of the following values:
0 successful completion
1 Syntax error
2 Runtime error
EXTERNAL INFLUENCES
Use environment variable SCC_DATA to specify an alternative directory
for the SCC data files. Should be an absolute path.
COPYRIGHT
scc-snap2html is free software under the terms of the GNU General Public
License. Copyright (C) 2001-2004 Open Challenge B.V.,
2004-2005 OpenEyeT Professional Services, 2005-2015 QNH.
FILES
/var/opt/scc/data/style.css - stylesheet for snapshot (and logbook)
SEE ALSO
scc(1), scc-cmp(1), scc-collect(1), scc-log(1), scc-log2html(1),
scc-plugin(1), scc-snap2html(1), scc(4), scc(5)
VERSION
$Revision: 5917 $
) ;;
echo "${ProgName}: alternative SCC_DATA (${SCC_DATA}) should be an absolute path" >&2
xit 2;;
ac
port TMPDIR=${SCC_TMP}
port TMP=${SCC_TMP}
port SHELL=/bin/sh
Perform the security settings before calling any program.
TH=/sbin:/usr/sbin:/usr/bin:/bin; export PATH
ask 077
[ ! -w ${SCC_DATA} ]
en
cho "${ProgName}: insufficient permissions to write in data directory: ${SCC_DATA}" >&2
xit 2
${SCC_TMP}
D_LINE="${ProgName} [ -h|--help ] [ -s|--standalone ] <name>"
NTAX_ERROR="Syntax error, use: ${CMD_LINE}"
andalone=""
ile [ $# -gt 0 ]
ase "${1}" in
s|--standalone) standalone="yes"
shift 1;;
h|--help) echo "${CMD_LINE}"
exit 0;;
*) echo "${SYNTAX_ERROR}" >&2
exit 1;;
) break;;
sac
ne
[ $# -ne 1 ]
en
cho "${SYNTAX_ERROR}" >&2
xit 1
${SCC_BIN}/scc_modules/scc_utils
-r ${SCC_CONF}/scc-localize ] && . ${SCC_CONF}/scc-localize
ndom="$(get_RANDOM)"
port TMP_FILE=${SCC_TMP}/scc_html_$$_${random}
port TMP_STATS=${SCC_TMP}/scc_tmp_stats_$$_${random}
port IND_FILE=${SCC_TMP}/scc_ind_$$_${random}
port HLP_CLASSES=${SCC_TMP}/scc_help_c_$$_${random}
port HLP_USED=${SCC_TMP}/scc_help_u_$$_${random}
port STAT_DATA=${SCC_TMP}/scc_stats_$$_${random}
ap 'rm -f ${TMP_FILE} ${TMP_STATS} ${IND_FILE} ${HLP_CLASSES} ${HLP_USED} ${STAT_DATA}' 0
ap "exit 2" 1 2 3 15
e_process_data()
{
Replace special HTML-characters in input.
Anything that does not start with fix: or var: is unexpected.
Remove the special tags used by scc-collect and scc-log to
detect and handle changes in user modules.
ed -e '/^var:MoDuLe:start::/d' \
-e '/^var:MoDuLe:end::/d' \
-e 's/&/\&/g' \
-e 's/</\</g' \
-e 's/>/\>/g' \
-e "s/'/\'/g" \
-e 's/"/\"/g' |
wk '/^fix:|^var:|^hlp:|^stats:/ { print; next }
{ print "fix:unexpected data::" $0 }'
}
P_NAME="<A NAME=cfg_top></A>"
L_SEP=" "
P_URL="<A HREF=\"#cfg_top\">Top</A>${URL_SEP}"
Generate the heading of the HTML file.
n_header()
{
cho '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'
cho "<HTML lang=\"en\">"
cho "<HEAD>"
f [ -z "${standalone}" ]
hen
echo '<LINK HREF="style.css" REL="stylesheet" TYPE="text/css">'
lse
if [ -f "${SCC_DATA}/style.css" ]
then
echo '<style TYPE="text/css">'
cat "${SCC_DATA}/style.css"
echo "</style>"
fi
i
cho "<TITLE>Configuration: ${1}</TITLE>"
cho "</HEAD>"
cho "<BODY>"
cho "<DIV class=SCC_SNAP>";
cho "${TOP_NAME}"
cho "<H1>"
cho " Configuration: ${1}"
cho "</H1>"
cho "<DIV class=SCC_SNAP_NAV>";
DO NOT CHANGE THE FOLLOWING HTML-CODE WITHOUT CONSULTING scc.cgi IN scc-srv
cho "<H2>"
f [ -z "${standalone}" ]
hen
echo " <A HREF=\"index.html\">Home</A>${URL_SEP}"
echo " <A HREF=\"scc.${1}.log.html\">Logbook</A>${URL_SEP}"
i
f [ -s ${STAT_DATA} ]
hen
echo " <A HREF=\"#statistics\">Statistics</A>${URL_SEP}"
i
cho " <A HREF=\"#legend\">Legend</A>"
cho "</H2>"
cho "</DIV><!-- class=SCC_SNAP_NAV -->";
}
epare_help()
{
Get all the help classifications from the snap-shot.
ed -n \
-e 's/::.*//' \
-e 's/\/_/g' \
-e '/^hlp:/p' ${TMP_FILE} 2>/dev/null |
ort -u >${HLP_CLASSES}
}
Initialize the file containing the classifications of the help-info that is referenced.
{HLP_USED}
Generate the entire hierarchical menu from the classifications in the data
n_menu()
{
cho "<DIV class=SCC_SNAP_MENU>";
Get all the hierarchical classifications from the snap-shot.
Do not sort, we depend on the order of the collect-script.
rep "^[fv][ia][xr]:" |
ed -e 's/^var://' \
-e 's/^fix://' \
-e 's/::.*//' \
-e 's/\/_/g' |
wk -F: '{
# Make sure that each classification is treated once
if ( done[ $0 ] )
{
next;
}
done[ $0 ] = 1;
# Format of the input is (for level 3 classification):
# a:b:c
# Generate:
# - level 1 menu item: a
# - level 2 menu item: a:b
# - level 3 menu item: a:b:c
# Each line of output has the following format:
# <level>:<id of parent menu>:<id of menu-item>:<classification>
for ( level = 1; level <= NF; level++ )
{
if ( level == 1 )
{
prev_id = 11;
class = $1;
}
else
{
prev_id = id[ class ];
class = sprintf( "%s:%s", class, $level );
}
if ( ! id[ class ] )
{
# One line may cause several new submenus.
id[ class ] = ( 10 * NR ) + level;
# Use broad, fixed width numbers to enable usage of busybox sort to order the data.
printf( "%03.3d:%010.10d:%010.10d:%s\n", level, prev_id, NR, class );
}
}
' - |
ort |
wk -F: '/^hlp:/ {
# Format of the data is:
# hlp:<classification>::<data>
class = $2;
for ( i = 3; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
class = sprintf( "%s_%s", class, $i );
}
gsub( /[^A-Za-z0-9_.-]/, "_", class ); # W3C restrictions and no ":".
help_avail[ class ] = 1;
next;
}
{
# Format of the data is:
# <level>:<submenu-id>:<line-number>:<classification>
if ( $1 != prev_level )
{
prev_level=$1;
if ( NR > 1 )
{
print "<HR>";
}
}
if ( ( $1 > 1 ) && ( $2 != prev_menu ) )
{
# Produce the heading of a submenu (name, top-reference, optional help, label).
print "<H3>"
# Produce the name of this submenu.
url = $4;
for ( i = 5; i < NF; i++ )
{
url = sprintf( "%s_%s", url, $i );
}
gsub( /[^A-Za-z0-9_.-]/, "_", url ); # W3C restrictions and no ":".
printf( " <A NAME=\"cfg_%s\"></A>\n", url );
print " " u; # Reference to TOP
if ( help_avail[ url ] )
{
printf( " <A HREF=\"#hlp_%s\" TITLE=\"%s\">Help</A>%s", url, url, s );
print "hlp_" url >>t; # Indicate that this help-info is referenced.
}
# Produce references to parent menus.
url = "cfg"
for ( i = 4; i < ( NF - 1 ); i++ )
{
url = sprintf( "%s_%s", url, $i );
gsub( /[^A-Za-z0-9_.-]/, "_", url ); # W3C restrictions and no ":".
title = url;
sub( "^cfg_", "", title );
printf( " <A HREF=\"#%s\" TITLE=\"%s\">%s</A> - \n", url, title, $i );
}
print " " $i;
print "</H3>"
prev_menu = $2;
}
url = $4;
for ( i = 5; i <= NF; i++ )
{
url = sprintf( "%s_%s", url, $i );
}
gsub( /[^A-Za-z0-9_.-]/, "_", url ); # W3C restrictions and no ":".
printf( " <A HREF=\"#cfg_%s\" TITLE=\"%s\">%s</A><BR>\n", url, url, $NF );
}' \
s="${URL_SEP}" \
t="${HLP_USED}" \
u="${TOP_URL}" \
${HLP_CLASSES} \
-
cho "</DIV><!-- class=SCC_SNAP_MENU -->";
}
Generate all the data
n_data()
{
elp_classes="${1}"
ata="${2}"
cho "<DIV class=SCC_SNAP_ENTRY>";
The entire menu-structure has been built.
Show all the data.
To "group" all data per classification, we rewrite the snapshot.
- each "new" classification is prefixed by the line:
<first-line-number>:0:<class>
- each line of a snapshot is extended with:
<first-line-number-of-classification>:<line-number>:<data>
By sorting the resulting file, all data with the same classifications are
grouped together, while the order of the lines within a classification
is preserved from the original snapshot.
cat "${help_classes}"
awk -F":" '/^fix:|^var:/ {
# Get the classification, ignore the first part: fix/var.
class = $2;
for ( i = 3; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
class = sprintf( "%s - %s", class, $i );
}
if ( ! id[ class ] )
{
id[ class ] = NR;
printf( "%010.10d:%010.10d:%s:%s", NR, 0, class, $2 );
for ( i = 3; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
printf( ":%s", $i );
}
print "";
}
# Use broad, fixed width numbers to enable usage of busybox sort to order the data.
printf( "%010.10d:%010.10d:%s\n", id[ class ], NR, $0 );
}' "${data}" |
sort
|
wk -F":" '
^hlp/ {
# Syntax of each line:
#hlp:<classification>
help_avail[ $0 ]=1;
next;
}
^[0-9]/ {
# Here we process the snapshot, prefixed with two numbers to group all data.
if ( $2 == 0 )
{
# This is the start of a new classification.
# Format is: <id>:<0>:<header of classification>:<classification>
if ( started )
{
print "</PRE>"
general=0;
}
started = 1;
print "<HR>"
printf( "<H3>%s", u );
# Check whether help-info is available.
class="hlp";
for ( i = 4; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
class=sprintf( "%s:%s", class, $i );
}
if ( help_avail[ class ] )
{
gsub( /[^A-Za-z0-9_.-]/, "_", class ); # W3C restrictions and no ":".
title = class;
sub( "^hlp_", "", title );
printf( "<A HREF=\"#%s\" TITLE=\"%s\">Help</A>%s", class, title, s );
print class >>t;
}
class=$4;
for ( i = 5; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
class=sprintf( "%s_%s", class, $i );
}
gsub( /[^A-Za-z0-9_.-]/, "_", class ); # W3C restrictions and no ":".
printf( "<A NAME=\"cfg_%s\"></A>", class ); # Produce the name of this sub-menu/data
# References to all previous menus in the hierarchy.
tag = "";
sep = "";
for ( depth = 4; ( depth < NF ) && ( length( $(depth + 1) ) > 0 ); depth++ )
{
if (length( tag ) == 0 )
{
tag = $depth;
}
else
{
tag = sprintf( "%s_%s", tag, $depth );
}
gsub( /[^A-Za-z0-9_.-]/, "_", tag ); # W3C restrictions and no ":".
printf( "%s<A HREF=\"#cfg_%s\" TITLE=\"%s\">%s</A>\n", sep, tag, tag, $depth );
sep = " - ";
}
print " " sep $depth;
print "</H3>";
print "<PRE>"
if ( $3 == "general" )
{
general=1;
}
next;
}
# Format is: <id>:<line-number>:<classification>::<data>
if ( $3 == "hlp" )
{
next; # help-info is processed later in this program.
}
# Show var-data in a different color.
var_font_start=""
var_font_end=""
if ( ( $3 != "fix" ) && ( c != "no_color" ) )
{
var_font_start=sprintf( "<span class=\"scc_var\">" );
var_font_end="</span>"
}
if ( general )
{
# Format of the data is:
#<classID>:<lineNR>:fix_or_var:general::<label>:<data>
#1 2 3 4 5 6 7
printf( "%s", var_font_start );
sub( /^[ ]*/, "", $7 ); # align data with ":" after the label
printf( "%-25s: %s", $6, $7 );
for ( i = 8; i <= NF; i++ )
{
printf( ":%s", $i );
}
print var_font_end;
}
else
{
# Format of the data is:
#<classID>:<lineNR>:fix_or_var:<class>::<data>
#1 2 3 4
# We only want to display the data, ignore leading fields.
for ( i = 4; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{ }
i++; # skip ::
# Dennis Bieling indicated that sprintf cannot be used on Debian for lines containing too many fields.
if ( length( $i ) > 0 || i < NF )
{
printf( "%s%s", var_font_start, $i );
for ( i++; i <= NF; i++ )
{
printf( ":%s", $i );
}
printf( "%s\n", var_font_end );
}
else
{
print " ";
}
}
next;
ND {
print "</PRE>"
}' s="${URL_SEP}" \
t="${HLP_USED}" \
u="${TOP_URL}" \
-
cho "</DIV><!-- class=SCC_SNAP_ENTRY -->";
}
Show all the help-info
n_help()
{
Determine the available classes.
cho "<DIV class=SCC_SNAP_HELP>";
wk -F: '
^hlp_/ {
hlp_used[ $0 ] = 1;
next;
}
^hlp:/ {
class=$0;
sub( /::.*/, "", class );
gsub( /[^A-Za-z0-9_.-]/, "_", class ); # W3C restrictions and no ":".
if ( ! hlp_used[ class ] )
{
next;
}
if ( class != prev_class )
{
if ( length( prev_class ) )
{
print "</PRE>";
# Some config files can be checked more than once.
# Show the helpinfo only once to avoid double definition of NAME entry.
hlp_used[ prev_class ] = 0;
}
prev_class=class;
print "<HR>";
printf( "<A NAME=\"%s\"></A>\n", class );
printf( "<H3>%s", u );
back="cfg";
for ( i = 2; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
back=sprintf( "%s_%s", back, $i );
}
gsub( /[^A-Za-z0-9_.-]/, "_", back ); # W3C restrictions and no ":".
title = back;
sub( "^cfg_", "", title );
printf( "<A HREF=\"#%s\" TITLE=\"%s\">Back</A> ", back, title );
printf( "%s", $2 );
for ( i = 3; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{
printf( " - %s", $i );
}
print "</H3>";
print "<PRE>"
}
# Ignore the classification.
for ( i = 1; ( i <= NF ) && ( length( $i ) > 0 ); i++ )
{ }
i++; # skip ::
if ( length( $i ) > 0 || i < NF )
{
data=$i
for ( i++; i <= NF; i++ )
{
data=sprintf( "%s:%s", data, $i );
}
print data;
}
else
{
print " ";
}
}
END {
if ( length( prev_class ) )
{
print "</PRE>"
}
}' u="${TOP_URL}"
cho "</DIV><!-- class=SCC_SNAP_HELP -->";
}
Generate the legend and terminate the html file
n_trailer()
{
cho "<HR>"
cho "<H2>${TOP_URL}<A NAME=legend>Legend</A></H2>"
cho "<P>"
cho "Fix data in the snapshot has a default color."
cho "Variable data in the snapshot has a specific <span class=\"scc_var\">color</span>."
cho "</P>"
cho "<HR>"
cho "<P>Generated by SCC version 1.23.185 (© <A HREF=\"http://www.qnh.eu\">QNH</A>) on $(date)</P>"
cho "</DIV><!-- class=SCC_SNAP -->";
cho "</BODY>"
cho "</HTML>"
}
Generate statistics from data in the snapshot.
n_stats()
{
Generate the statistics sub-menu with the Profiling and the Class counters.
cho "<DIV class=SCC_SNAP_STATS>";
cho "<HR>"
cho "<H3><A NAME=statistics>Statistics</A>${URL_SEP}"
cho " ${TOP_URL}"
cho " <A HREF=\"#stats_profiling\">Profiling</A>${URL_SEP}"
cho " <A HREF=\"#stats_classes\">Class counters</A>"
cho "</H3>"
cho "<HR>"
cho "<H4><A NAME=stats_profiling></A>Profiling${URL_SEP}${TOP_URL}<A HREF=\"#statistics\">Statistics</A></H4>"
Format of profiling data:
stats:profiling::<time>:<total_time>:<partial_time>:<module>:<label>
wk -F: '/^stats:profiling::/ {
if ( profiling_hdr == 0 )
{
class="Odd";
print "<TABLE CLASS=SCC SUMMARY=\"Performance of SCC modules\" BORDER CELLSPACING=1 CELLPADDING=1>"
print "<THEAD>";
printf( "<TR class=%s>\n", class );
print " <TH>Time</TH>";
print " <TH>Total seconds</TH>";
print " <TH>Module seconds</TH>";
print " <TH>Module</TH>";
print " <TH>Label</TH>";
print "</TR>";
print "</THEAD>";
print "<TBODY>";
profiling_hdr = 1;
}
if ( class != "Odd" )
{
class = "Odd";
}
else
{
class = "Even";
}
printf( "<TR class=%s>\n", class );
print " <TD class=Odd>" $4 "</TD>";
print " <TD class=Even align=right>" $5 "</TD>";
print " <TD class=Odd align=right>" $6 "</TD>";
print " <TD class=Even>" $7 "</TD>";
if ( length( $8 ) == 0 )
{
$8 = " ";
}
print " <TD class=Odd>" $8 "</TD>";
print "</TR>";
next;
}
END {
if ( profiling_hdr > 0 )
{
print "</TBODY>";
print "</TABLE>"
}
}' ${1}
cho "<H4><A NAME=stats_classes>Classes</A>${URL_SEP}${TOP_URL}<A HREF=\"#statistics\">Statistics</A></H4>"
cho "<P>Help-info is excluded from the fix/var and class counters.</P>"
Format of fix_var data:
stats:fix_var::<lavel>:<cnt>:<perc>
wk -F: '/^stats:fix_var::/ {
if ( profiling_hdr == 0 )
{
class="Odd";
print "<TABLE CLASS=SCC SUMMARY=\"Counters for fix and var data\" BORDER CELLSPACING=1 CELLPADDING=1>"
print "<THEAD>";
printf( "<TR class=%s>\n", class );
print " <TH>Category</TH>";
print " <TH>Count</TH>";
print " <TH>Percentage</TH>";
print "</TR>";
print "</THEAD>";
print "<TBODY>";
profiling_hdr = 1;
}
if ( class != "Odd" )
{
class = "Odd";
}
else
{
class = "Even";
}
printf( "<TR class=%s>\n", class );
print " <TD class=Odd>" $4 "</TD>";
print " <TD class=Even align=right>" $5 "</TD>";
print " <TD class=Odd align=right>" $6 "</TD>";
print "</TR>";
next;
}
END {
if ( profiling_hdr > 0 )
{
print "</TBODY>";
print "</TABLE>"
}
}' ${1}
cho "<BR>"
Format of classes data:
stats:classes::<main>:<sub>:<main_cnt>:<main_perc>:<sub_cnt>:<sub_perc>
wk -F: '/^stats:classes::/ {
if ( profiling_hdr == 0 )
{
class="Odd";
print "<TABLE CLASS=SCC SUMMARY=\"Counters for first two levels of classifications\" BORDER CELLSPACING=1 CELLPADDING=1>"
print "<THEAD>";
printf( "<TR class=%s>\n", class );
print " <TH>Main class</TH>";
print " <TH>Sub class</TH>";
print " <TH>Main cnt</TH>";
print " <TH>Main perc</TH>";
print " <TH>Sub cnt</TH>";
print " <TH>Sub perc</TH>";
print "</TR>";
print "</THEAD>";
print "<TBODY>";
profiling_hdr = 1;
}
if ( $4 != prev_main )
{
if ( class != "Odd" )
{
class = "Odd";
}
else
{
class = "Even";
}
# display only main label, count and perc.
main_url = $4;
gsub( /[^A-Za-z0-9_.-]/, "_", main_url ); # W3C restrictions and no ":".
printf( "<TR class=%s>\n", class );
printf( " <TD class=Odd><A HREF=\"#cfg_%s\" TITLE=\"%s\">%s</A></TD>\n", main_url, main_url, $4 );
print " <TD class=Even> </TD>";
print " <TD class=Odd align=right>" $6 "</TD>";
print " <TD class=Even align=right>" $7 "</TD>";
print " <TD class=Odd> </TD>";
print " <TD class=Even> </TD>";
print "</TR>";
prev_main = $4;
}
if ( length( $5 ) > 0 )
{
if ( class != "Odd" )
{
class = "Odd";
}
else
{
class = "Even";
}
sub_url = sprintf( "%s_%s", prev_main, $5 );
gsub( /[^A-Za-z0-9_.-]/, "_", sub_url ); # W3C restrictions and no ":".
printf( "<TR class=%s>\n", class );
print " <TD class=Odd> </TD>";
printf( " <TD class=Even><A HREF=\"#cfg_%s\" TITLE=\"%s\">%s</A></TD>\n", sub_url, sub_url, $5 );
print " <TD class=Odd> </TD>";
print " <TD class=Even> </TD>";
print " <TD class=Odd align=right>" $8 "</TD>";
print " <TD class=Even align=right>" $9 "</TD>";
print "</TR>";
}
next;
}
END {
if ( profiling_hdr > 0 )
{
print "</TBODY>";
print "</TABLE>"
}
}' ${1}
cho "</DIV><!-- class=SCC_SNAP_STATS -->";
}
e_process_data >${TMP_FILE}
ep "^stats:" <${TMP_FILE} >${STAT_DATA}
epare_help <${TMP_FILE} >${HLP_CLASSES}
Generate the entire HTML file:
(
en_header ${1} # No input required
en_menu <${TMP_FILE} # also writes in ${HLP_USED}
en_data "${HLP_CLASSES}" "${TMP_FILE}"
f [ -s ${STAT_DATA} ]
hen
gen_stats ${STAT_DATA}
i
at ${HLP_USED} ${TMP_FILE} | gen_help
en_trailer # No input required
)
it 0