54 use strict; |
54 use strict; |
55 use Cwd; |
55 use Cwd; |
56 |
56 |
57 my $version = "2.2 (27/02/08)"; |
57 my $version = "2.2 (27/02/08)"; |
58 |
58 |
59 getopts("MHpx:N:A:vVr:R:hnf"); |
59 getopts("MHpx:N:A:vVr:R:hnfo:"); |
60 our($opt_M, $opt_H, $opt_p, $opt_x, $opt_N, $opt_A, $opt_v, $opt_V, $opt_r, $opt_R, $opt_h, $opt_n, $opt_f); |
60 our($opt_M, $opt_H, $opt_p, $opt_x, $opt_N, $opt_A, $opt_v, $opt_V, $opt_r, $opt_R, $opt_h, $opt_n, $opt_f, $opt_o); |
|
61 |
|
62 my $outputPath = processPathArgument($opt_o); |
61 |
63 |
62 if ($opt_h) |
64 if ($opt_h) |
63 { |
65 { |
64 print <<HELP; |
66 print <<HELP; |
65 Usage: |
67 Usage: |
305 } else { |
309 } else { |
306 my $viewsToDisplay = int($rowsToDisplay / $maxRowsToDisplay) + 1; |
310 my $viewsToDisplay = int($rowsToDisplay / $maxRowsToDisplay) + 1; |
307 my $rowsPerView = int(($rowsToDisplay + $viewsToDisplay - 1) / $viewsToDisplay); |
311 my $rowsPerView = int(($rowsToDisplay + $viewsToDisplay - 1) / $viewsToDisplay); |
308 my $viewNumber = 0; |
312 my $viewNumber = 0; |
309 createViewMap(); |
313 createViewMap(); |
|
314 createIpcMap(); |
310 while ($beginRow < $totalRows) { |
315 while ($beginRow < $totalRows) { |
311 $endRow = $beginRow + $rowsPerView - 1; |
316 $endRow = $beginRow + $rowsPerView - 1; |
312 if ($endRow >= $totalRows) { |
317 if ($endRow >= $totalRows) { |
313 drawView($beginRow, $totalRows - 1, $viewNumber, $viewNumber); # last view |
318 drawView($beginRow, $totalRows - 1, $viewNumber, $viewNumber); # last view |
314 } else { |
319 } else { |
351 my $fileName = "log"; |
357 my $fileName = "log"; |
352 if ($viewNumber != $lastViewNumber) { |
358 if ($viewNumber != $lastViewNumber) { |
353 $fileName .= $viewNumber; |
359 $fileName .= $viewNumber; |
354 } |
360 } |
355 |
361 |
356 open SVG, ">html/${fileName}.svg" || die "Cannot open html/${fileName}.svg for writing\n"; |
362 my $path = $outputPath . "html/${fileName}.svg"; |
|
363 open SVG, ">$path" || die "Cannot open $path for writing\n"; |
357 #open RTTTL, ">html/${fileName}.rtttlpre" || die "Cannot open html/${fileName}.rttlpre for writing\n"; |
364 #open RTTTL, ">html/${fileName}.rtttlpre" || die "Cannot open html/${fileName}.rttlpre for writing\n"; |
358 |
365 |
359 outputDocHeader($screenWidth, $screenHeight); |
366 outputDocHeader($screenWidth, $screenHeight); |
360 drawObjectNames(0); |
|
361 updateObjectViewList($viewNumber); |
367 updateObjectViewList($viewNumber); |
362 drawObjectLifelines($beginRow, $endRow, $screenHeight); |
368 drawObjectLifelines($beginRow, $endRow, $screenHeight); |
|
369 drawObjectNames(0); |
363 drawActivities($beginRow, $endRow, $screenHeight, $viewNumber); |
370 drawActivities($beginRow, $endRow, $screenHeight, $viewNumber); |
364 my @labelsOnPage = (); |
371 my @labelsOnPage = (); |
365 my @objectsDestroyed = (); |
372 my @objectsDestroyed = (); |
366 my @objectsCreated = (); |
373 my @objectsCreated = (); |
367 drawSequences($beginRow, $endRow, 1, \@labelsOnPage, \@objectsCreated, \@objectsDestroyed); |
374 my @ipc = (); |
|
375 drawSequences($beginRow, $endRow, 1, \@labelsOnPage, \@objectsCreated, \@objectsDestroyed, \@ipc); |
368 outputViewMap($viewNumber, $lastViewNumber, \@labelsOnPage, \@objectsCreated, \@objectsDestroyed); |
376 outputViewMap($viewNumber, $lastViewNumber, \@labelsOnPage, \@objectsCreated, \@objectsDestroyed); |
|
377 outputIpcMap($viewNumber, $lastViewNumber, \@ipc); |
369 outputDocFooter(); |
378 outputDocFooter(); |
370 |
379 |
371 close SVG; |
380 close SVG; |
372 #close RTTTL; |
381 #close RTTTL; |
373 |
382 |
965 $colour =~ s/^!//; |
977 $colour =~ s/^!//; |
966 outputText($x + $rotatedTextOffset, $name, $currentY, "begin", $colour, qq{id="$name" onclick="debugEvent(evt)" transform="$transform" font-size="12" font-family="sans-serif"}); |
978 outputText($x + $rotatedTextOffset, $name, $currentY, "begin", $colour, qq{id="$name" onclick="debugEvent(evt)" transform="$transform" font-size="12" font-family="sans-serif"}); |
967 } |
979 } |
968 else |
980 else |
969 { |
981 { |
970 outputText($i->{X}, $name, $currentY, "middle", $colour, qq{id="$name" onclick="debugEvent(evt)"}); |
982 my $stagger = ($i->{colno} & 1); |
|
983 outputText($i->{X}, $name, $currentY + ($stagger * $incrementY), "middle", $colour, qq{id="$name" onclick="debugEvent(evt)"}); |
971 } |
984 } |
972 } |
985 } |
973 incrementY(); |
986 incrementY(2); |
974 } |
987 } |
975 |
988 |
976 # |
989 # |
977 # Test whether a value is within a certain (start,end] range inclusive. |
990 # Test whether a value is within a certain (start,end] range inclusive. |
978 # |
991 # |
1135 # Partitioning: how do popups work ? |
1148 # Partitioning: how do popups work ? |
1136 # |
1149 # |
1137 |
1150 |
1138 sub drawSequences($$$$$$) |
1151 sub drawSequences($$$$$$) |
1139 { |
1152 { |
1140 my ($startRow, $endRow, $drawFlag, $labelsOnPageRef, $objectsCreatedRef, $objectsDestroyedRef) = @_; |
1153 my ($startRow, $endRow, $drawFlag, $labelsOnPageRef, $objectsCreatedRef, $objectsDestroyedRef, $ipcRef) = @_; |
1141 my $nextLabel = ""; |
1154 my $nextLabel = ""; |
1142 |
1155 |
1143 # startRow/endRow = start/end row of displayed area (inclusive) |
1156 # startRow/endRow = start/end row of displayed area (inclusive) |
1144 # absoluteRow = increments through all rows that have an object to display, whether in displayed area or not. |
1157 # absoluteRow = increments through all rows that have an object to display, whether in displayed area or not. |
1145 # rows = Increments for each row that contains an object to display, but only when $absoluteRow moves |
1158 # rows = Increments for each row that contains an object to display, but only when $absoluteRow moves |
1148 my $rows = 0; |
1161 my $rows = 0; |
1149 my $absoluteRow = 0; |
1162 my $absoluteRow = 0; |
1150 my $drawDone = 0; |
1163 my $drawDone = 0; |
1151 my $inRange = 0; |
1164 my $inRange = 0; |
1152 my $lastPopupText = ""; # text of last "pn" action |
1165 my $lastPopupText = ""; # text of last "pn" action |
1153 |
|
1154 foreach my $ref (@sequences) { |
1166 foreach my $ref (@sequences) { |
1155 my $action = $ref->{Action}; |
1167 my $action = $ref->{Action}; |
1156 |
1168 |
1157 $inRange = IsInRangeInclusive($absoluteRow, $startRow, $endRow); |
1169 $inRange = IsInRangeInclusive($absoluteRow, $startRow, $endRow); |
1158 if ($action eq "t") { |
1170 if ($action eq "t") { |
1167 my $colour = ""; |
1179 my $colour = ""; |
1168 if ($text =~ /\s*\{(\d+,\d+,\d+)\}\s*(.+)/) { |
1180 if ($text =~ /\s*\{(\d+,\d+,\d+)\}\s*(.+)/) { |
1169 $colour .= "rgb($1)"; |
1181 $colour .= "rgb($1)"; |
1170 $text = $2; |
1182 $text = $2; |
1171 } |
1183 } |
1172 my $attrs = generatePopupAttrs(\$lastPopupText, qq{id="$ref->{Object}->{Name}"}); |
1184 my $name = $ref->{Object}->{Name}; |
|
1185 my $attrs = generatePopupAttrs(\$lastPopupText, qq{id="$name"}); |
1173 outputText($objX + $lifelineTextLeftMargin, $text, $currentY, "begin", $colour, $attrs); |
1186 outputText($objX + $lifelineTextLeftMargin, $text, $currentY, "begin", $colour, $attrs); |
1174 $drawDone = 1; |
1187 $drawDone = 1; |
1175 # support for putting threads into the view map |
1188 # support for putting threads into the view map |
1176 $text = $ref->{Text}; |
1189 $text = $ref->{Text}; |
1177 if ($text =~ m/^\(Thread "(.*)" (\w+)\)$/) { |
1190 if ($text =~ m/^\(Thread "(.*)" (\w+)\)$/) { |
1178 if ($2 eq "Created") { |
1191 if ($2 eq "Created") { |
1179 push @{$objectsCreatedRef}, $1; |
1192 push @{$objectsCreatedRef}, $1; |
1180 } elsif ($2 eq "Destroyed") { |
1193 } elsif ($2 eq "Destroyed") { |
1181 push @{$objectsDestroyedRef}, $1; |
1194 push @{$objectsDestroyedRef}, $1; |
1182 } |
1195 } |
|
1196 } |
|
1197 if ($name =~ s/^!//) { |
|
1198 push @{$ipcRef}, $ref; |
1183 } |
1199 } |
1184 } else { |
1200 } else { |
1185 fakeUpCreationDeletionIfRequired($ref->{Object}, $absoluteRow); |
1201 fakeUpCreationDeletionIfRequired($ref->{Object}, $absoluteRow); |
1186 } |
1202 } |
1187 } |
1203 } |
1382 { |
1398 { |
1383 # Note: have (possibly) incremented absoluteRow above, so re-calculate $inRange |
1399 # Note: have (possibly) incremented absoluteRow above, so re-calculate $inRange |
1384 $inRange = IsInRangeInclusive($absoluteRow, $startRow, $endRow); |
1400 $inRange = IsInRangeInclusive($absoluteRow, $startRow, $endRow); |
1385 if ($inRange) |
1401 if ($inRange) |
1386 { |
1402 { |
1387 # drawObjectNames() increments Y once, and we increment Y once for |
1403 # drawObjectNames() increments Y twice (for stagger), and we increment Y once for |
1388 # spacing, so we occupy two rows here. |
1404 # spacing, so we occupy three rows here. |
1389 $rows += 2; |
1405 $rows += 3; |
1390 if ($drawFlag == 1) |
1406 if ($drawFlag == 1) |
1391 { |
1407 { |
1392 drawObjectNames(1); |
1408 drawObjectNames(1); |
1393 incrementY(); |
1409 incrementY(); |
1394 } |
1410 } |
1395 } |
1411 } |
1396 $absoluteRow += 2; |
1412 $absoluteRow += 3; # 2 + 1 for stagger |
1397 } |
1413 } |
1398 } |
1414 } |
1399 return $rows; |
1415 return $rows; |
1400 } |
1416 } |
1401 |
1417 |
1697 # HTML Embedder routines # |
1713 # HTML Embedder routines # |
1698 ########################## |
1714 ########################## |
1699 |
1715 |
1700 sub createViewMap() |
1716 sub createViewMap() |
1701 { |
1717 { |
1702 open MAP, ">logmap.html" || die "Cannot open logmap.html for writing\n"; |
1718 my $path = $outputPath . "html/logmap.html"; |
|
1719 open MAP, ">$path" || die "Cannot open $path for writing\n"; |
1703 print MAP "<html>\n<body>\n"; |
1720 print MAP "<html>\n<body>\n"; |
1704 |
1721 |
1705 # Begin page label/time table |
1722 # Begin page label/time table |
1706 print MAP qq { <table border="1" style="text-align: center">\n }; |
1723 print MAP qq { <table border="1" style="text-align: center">\n }; |
1707 print MAP qq { <tr><th>Page</th><th colspan="2">Lines</th><th colspan="2">Times</th><th>Objects Created</th><th>Objects Destroyed</th></tr>\n }; |
1724 print MAP qq { <tr><th>Page</th><th colspan="2">Lines</th><th colspan="2">Times</th><th>Objects Created</th><th>Objects Destroyed</th></tr>\n }; |
1828 $obj->{LastPage} = $viewNumber; |
1845 $obj->{LastPage} = $viewNumber; |
1829 } |
1846 } |
1830 } |
1847 } |
1831 } |
1848 } |
1832 |
1849 |
|
1850 sub createIpcMap() |
|
1851 { |
|
1852 my $path = $outputPath . "html/ipcmap.html"; |
|
1853 open IPC, ">$path" || die "Cannot open $path for writing\n"; |
|
1854 print IPC "<html><head>\n"; |
|
1855 print IPC qq{<style type="text/css">}; |
|
1856 print IPC "td,th { text-align: left; font-family: courier new; white-space: nowrap ; font-size: smaller}\n"; |
|
1857 print IPC "</style></head><body>\n"; |
|
1858 |
|
1859 # Begin page label/time table |
|
1860 print IPC qq { <table border="1" >\n }; |
|
1861 print IPC qq { <tr><th style="text-align: center">Page</th><th style="text-align: center">EXEs...</th></tr>\n }; |
|
1862 } |
|
1863 |
|
1864 sub closeIpcMap() |
|
1865 { |
|
1866 print IPC "</table></body></html>\n"; |
|
1867 close IPC; |
|
1868 } |
|
1869 |
|
1870 my @IpcExeColumns = (); |
|
1871 |
|
1872 sub addToArrayUniquely($$) |
|
1873 { |
|
1874 my ($arrRef, $element) = @_; |
|
1875 foreach my $i ( @{$arrRef} ) { |
|
1876 if ($i eq $element) { |
|
1877 return; |
|
1878 } |
|
1879 } |
|
1880 push @{$arrRef}, $element; |
|
1881 } |
|
1882 |
|
1883 sub outputIpcMap($$$) |
|
1884 { |
|
1885 my ($viewNumber, $lastViewNumber, $ipcRef) = @_; |
|
1886 my %ipcExeUsed = (); |
|
1887 my $exe; |
|
1888 my $ipc; |
|
1889 foreach $ipc (@{$ipcRef}) { |
|
1890 $exe = $ipc->{Object}->{Name}; |
|
1891 addToArrayUniquely(\@IpcExeColumns, $exe); |
|
1892 $ipcExeUsed{$exe} = 1; |
|
1893 } |
|
1894 |
|
1895 # Page number in first column (two rows) |
|
1896 #my $style = qq{style="text-align: left; font-family: courier new; white-space: nowrap ; font-size: smaller"}; |
|
1897 print IPC qq {<tr><td rowspan="2" style="text-align: center">$viewNumber</td>\n}; |
|
1898 |
|
1899 # Second and subsequent columns showing the exe names |
|
1900 foreach $exe ( @IpcExeColumns ) { |
|
1901 my $exe2 = $exe; # why do things go wrong if I operate directly on $exe??? |
|
1902 $exe2 =~ s/^!//; |
|
1903 if (!defined($ipcExeUsed{$exe})) { |
|
1904 print IPC qq{<td style="text-align: center ; color: gray">$exe2</td>}; |
|
1905 } else { |
|
1906 print IPC qq{<td style="text-align: center">$exe2</td>}; |
|
1907 } |
|
1908 } |
|
1909 |
|
1910 # next row |
|
1911 print IPC qq{</tr>\n<tr>}; |
|
1912 # for each exe there is column... |
|
1913 my $rr; |
|
1914 foreach $rr ( @IpcExeColumns ) { |
|
1915 print IPC qq{<td>}; |
|
1916 # ...showing the IPCs |
|
1917 foreach my $ref ( @{$ipcRef} ) { |
|
1918 if ($ref->{Object}->{Name} eq $rr) { |
|
1919 print IPC qq{$ref->{Text}<br>}; |
|
1920 } else { |
|
1921 print IPC qq{<br>}; |
|
1922 } |
|
1923 } |
|
1924 print IPC qq{</td>}; |
|
1925 } |
|
1926 print IPC qq {</tr>\n}; |
|
1927 } |
1833 |
1928 |
1834 # |
1929 # |
1835 # Output the "0 1 2 3 4 ..." anchors representing the different views |
1930 # Output the "0 1 2 3 4 ..." anchors representing the different views |
1836 # |
1931 # |
1837 sub outputHTMLPageLinks($$$$) { |
1932 sub outputHTMLPageLinks($$$$) { |
1845 print HTML qq{ <a href="${htmlPathNotLastView}log$i.html">$i</a>\n}; |
1940 print HTML qq{ <a href="${htmlPathNotLastView}log$i.html">$i</a>\n}; |
1846 } else { |
1941 } else { |
1847 print HTML qq{ <a href="${htmlPathLastView}log.html">$i</a>\n}; |
1942 print HTML qq{ <a href="${htmlPathLastView}log.html">$i</a>\n}; |
1848 } |
1943 } |
1849 } |
1944 } |
|
1945 } |
|
1946 } |
|
1947 |
|
1948 sub processPathArgument($) |
|
1949 { |
|
1950 my $path = $_[0]; |
|
1951 if ($path) { |
|
1952 # ensure "/" at the end |
|
1953 if ($path !~ /\/$/) { |
|
1954 $path .= "/"; |
|
1955 } |
|
1956 mkdirp($path); |
|
1957 return $path; |
|
1958 } else { |
|
1959 return ""; |
|
1960 } |
|
1961 } |
|
1962 |
|
1963 sub mkdirp($) |
|
1964 { |
|
1965 my $dirName = @_[0]; |
|
1966 if ($dirName =~ m/^(.*)\//i) { |
|
1967 if ($1 ne "") { |
|
1968 mkdirp($1); |
|
1969 } |
|
1970 } |
|
1971 if (! -d $dirName) { |
|
1972 mkdir($dirName); |
1850 } |
1973 } |
1851 } |
1974 } |
1852 |
1975 |
1853 sub outputHTMLEmbedder($$$$$) |
1976 sub outputHTMLEmbedder($$$$$) |
1854 { |
1977 { |
1872 $htmlLinkPathLastView = "html/"; |
1995 $htmlLinkPathLastView = "html/"; |
1873 $htmlLinkPathNotLastView = "html/"; |
1996 $htmlLinkPathNotLastView = "html/"; |
1874 $svgPathInHtmlFile = "html/" . $fileName; |
1997 $svgPathInHtmlFile = "html/" . $fileName; |
1875 $mainPath = ""; |
1998 $mainPath = ""; |
1876 } |
1999 } |
1877 open HTML, ">${htmlPath}.html" || die "Cannot open ${htmlPath}.html for writing\n"; |
2000 my $path = $outputPath . $htmlPath . ".html"; |
|
2001 open HTML, ">$path" || die "Cannot open $path for writing\n"; |
1878 |
2002 |
1879 if (! $opt_f) { |
2003 if (! $opt_f) { |
1880 # DOCTYPE needed for "position: fixed" to work in IE |
2004 # DOCTYPE needed for "position: fixed" to work in IE |
1881 print HTML "<!--[if IE]>\n"; |
2005 print HTML "<!--[if IE]>\n"; |
1882 print HTML qq{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n}; |
2006 print HTML qq{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n}; |
1915 } |
2039 } |
1916 |
2040 |
1917 print HTML qq{<input type="button" value="Symbols" onclick="popupSymbols()">\n}; |
2041 print HTML qq{<input type="button" value="Symbols" onclick="popupSymbols()">\n}; |
1918 print HTML qq{<input type="button" value="Relations" onclick="popupRelations()">\n}; |
2042 print HTML qq{<input type="button" value="Relations" onclick="popupRelations()">\n}; |
1919 print HTML qq{<input type="button" value="Map" onclick="popupMap()">\n}; |
2043 print HTML qq{<input type="button" value="Map" onclick="popupMap()">\n}; |
|
2044 print HTML qq{<input type="button" value="IPC Map" onclick="popupIpcMap()">\n}; |
1920 print HTML qq{ Zoom%\n<input type="text" size=3 maxlength=3 onkeypress="zoom(this,event)" />\n}; |
2045 print HTML qq{ Zoom%\n<input type="text" size=3 maxlength=3 onkeypress="zoom(this,event)" />\n}; |
1921 |
2046 |
1922 if ($opt_f) { |
2047 if ($opt_f) { |
1923 # don't need the bottom page links if the fixed position ones are at the top |
2048 # don't need the bottom page links if the fixed position ones are at the top |
1924 outputHTMLPageLinks($viewNumber, $lastViewNumber, $htmlLinkPathNotLastView, $htmlLinkPathLastView); |
2049 outputHTMLPageLinks($viewNumber, $lastViewNumber, $htmlLinkPathNotLastView, $htmlLinkPathLastView); |
2008 } |
2133 } |
2009 |
2134 |
2010 // |
2135 // |
2011 |
2136 |
2012 function popupSymbols() { |
2137 function popupSymbols() { |
2013 symbols = window.open(mainPath + "logsym.html", "_blank", "width=400,resizable=yes,scrollbars=yes"); |
2138 symbols = window.open(mainPath + "html/logsym.html", "_blank", "width=400,resizable=yes,scrollbars=yes"); |
2014 } |
2139 } |
2015 |
2140 |
2016 function popupRelations() { |
2141 function popupRelations() { |
2017 relations = window.open(mainPath + "relations.html", "_blank", "resizable=yes,scrollbars=yes,status=yes"); |
2142 relations = window.open(mainPath + "html/relations.html", "_blank", "resizable=yes,scrollbars=yes,status=yes"); |
2018 relationsDefined = 1; |
2143 relationsDefined = 1; |
2019 } |
2144 } |
2020 |
2145 |
2021 function popupMap() { |
2146 function popupMap() { |
2022 relations = window.open(mainPath + "logmap.html", "_blank", "resizable=yes,scrollbars=yes,status=yes"); |
2147 relations = window.open(mainPath + "html/logmap.html", "_blank", "resizable=yes,scrollbars=yes,status=yes"); |
|
2148 } |
|
2149 |
|
2150 function popupIpcMap() { |
|
2151 relations = window.open(mainPath + "html/ipcmap.html", "_blank", "resizable=yes,scrollbars=yes,status=yes"); |
2023 } |
2152 } |
2024 |
2153 |
2025 // |
2154 // |
2026 |
2155 |
2027 function objectHighlightForwarder(id) { |
2156 function objectHighlightForwarder(id) { |