Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for allhelp.pl

(view source code of allhelp.pl as plain text)

  1. #!/usr/bin/perl
  2.  
  3. # allhelp.pl for Linux
  4. # Display help for the Bourne Shell's internal commands and reserved words
  5. # Written by Rob van der Woude
  6. # http://www.robvanderwoude.com
  7.  
  8. use strict;
  9. use warnings;
  10. use Config;
  11. use CGI qw(escapeHTML);
  12.  
  13. my $scriptver = '1.02';
  14.  
  15. # Abort if not running on Linux
  16. if ( lc( $Config{osname} ) ne 'linux' ) {
  17. 	print "This script will run on Linux systems only.";
  18. 	exit 1;
  19. }
  20.  
  21. my @cmds;
  22. my @builtins;
  23. my @coreutils;
  24. my @reserved;
  25. my %helplong;
  26. my %helpshort;
  27. my $outfile = 'allhelp_bash.html';
  28.  
  29. # Create a list of all internal commands for which help is available
  30. open( SHELL, "-|", "bash", "-c", "compgen -b" );
  31. while( <SHELL> ) {
  32. 	chomp;
  33. 	push( @builtins, $_ );
  34. }
  35. close( SHELL );
  36.  
  37. # Create a list of all reserved words for which help is available
  38. open( SHELL, "-|", "bash", "-c", "compgen -k" );
  39. while( <SHELL> ) {
  40. 	chomp;
  41. 	push( @reserved, $_ );
  42. }
  43. close( SHELL );
  44.  
  45. # Create a list of coreutils
  46. open( SHELL, '-|', 'bash', '-c', 'info | grep -F "(coreutils)"');
  47. while ( <SHELL> ) {
  48. 	chomp;
  49. 	if ( $_ =~ m/^\*\s+([a-z][a-z0-9]+):\s+\(coreutils\)\1/ ) {
  50. 		$_ =~ /^\*\s+([a-z][a-z0-9]+):\s+\(coreutils\)\1\s[^.]+\.\s+(.+)$/;
  51. 		push( @coreutils, $1 );
  52. 		my $anchor = &Anchor( $1 );
  53. 		$helpshort{ $anchor } = $2;
  54. 	}
  55. }
  56. close( SHELL );
  57.  
  58.  
  59. # Merge the lists of commands
  60. push( @cmds, @builtins );
  61. push( @cmds, @reserved );
  62. push( @cmds, @coreutils );
  63.  
  64. # Sort the list of commands, punction and numbers first
  65. @cmds = sort {
  66. 	if ( $a =~ m/^[a-z]/i and $b !~ m/^[a-z]/i ) {
  67. 		return 1;
  68. 	} elsif ( $a !~ m/^[a-z]/i and $b =~ m/^[a-z]/i ) {
  69. 		return -1;
  70. 	} else {
  71. 		return $a cmp $b;
  72. 	}
  73. } @cmds;
  74.  
  75. # Calculate available column width for 3 colums display with 3 characters spacing
  76. my $cols = `tput cols`;
  77. my $rows = `tput lines`;
  78. my $colwidth = int( ( $cols - 6 ) / 3 );
  79.  
  80. # First display the Linux version
  81. print &LinuxVer( ) . "\n\n";
  82.  
  83. # Display the list of commands in 3 columns
  84. for ( my $i = 0; $i < @cmds; $i += 3 ) {
  85. 	printf '%-' . $colwidth . 's', $cmds[$i];
  86. 	if ( $i + 1 < @cmds ) { printf '   %-' . $colwidth . 's', $cmds[$i+1]; }
  87. 	if ( $i + 2 < @cmds ) { printf '   %-' . $colwidth . 's', $cmds[$i+2]; }
  88. 	print "\n";
  89. }
  90.  
  91. # Display help for each command in the array
  92. foreach my $cmd ( @cmds ) {
  93. 	print "\nHelp for '$cmd'\n\n";
  94. 	my $anchor = &Anchor( $cmd );
  95. 	my $helptext = '';
  96. 	if ( grep { $_ eq $cmd } @coreutils ) {
  97. 		# Use info command for coreutils
  98. 		open( SHELL, "-|", "bash", "-c", "info $cmd | grep -F \"\"" );
  99. 		# Read resulting help text from STDOUT
  100. 		while ( <SHELL> ) {
  101. 			$helptext .= $_;
  102. 		}
  103. 		close( SHELL );
  104. 		if ( $helptext ) {
  105. 			$helptext =~ s/\342\200\230/'/g;
  106. 			$helptext =~ s/\342\200\231/'/g;
  107. 			$helptext =~ s/^\/([^\n]*\n){3}\d+\.\d+\s+//;
  108. 			$helptext =~ s/\n=+\n/\n/g;
  109. 			$helplong{ $anchor } = $helptext;
  110. 		}
  111. 	} else {
  112. 		# Use help command for reserved words and builtin commands
  113. 		# Escape the commands, otherwise bash may break on parenthesis
  114. 		my $esccmd = quotemeta( $cmd );
  115. 		# Run help command with escaped command name
  116. 		open( SHELL, "-|", "bash", "-c", "help $esccmd 2> /dev/null" );
  117. 		# Read resulting help text from STDOUT
  118. 		while ( <SHELL> ) {
  119. 			$helptext .= $_;
  120. 		}
  121. 		close( SHELL );
  122. 		if ( "$helptext" !~ m/^\s*$/g ) {
  123. 			$helplong{ $anchor } = $helptext;
  124. 			# Display help text
  125. 			print escapeHTML( $helptext );
  126. 			# Get short help text summary
  127. 			my $firstline = $cmd . ': ' . $cmd . '[^\n]*\n\s+';
  128. 			if ( $cmd ne $esccmd ) {
  129. 				$firstline = $esccmd . '[^a-z:\n]*: ' . $esccmd . '[^\n]*\n\s+';
  130. 			}
  131. 			"$helptext" =~ /$firstline((.|\n)*?)\n\s*\n/;
  132. 			$helpshort{ $anchor } = $1;
  133. 		}
  134. 	}
  135. }
  136.  
  137. print "\n\n";
  138.  
  139. # Remove commands from list if no help is available
  140. # Use reverse order to prevent skipping 1 each time an element is removed from the array
  141. for ( my $i = @cmds - 1; $i >= 0; $i-- ) {
  142. 	my $cmd = $cmds[$i];
  143. 	my $anchor = &Anchor( $cmd );
  144. 	unless ( exists( $helplong{ $anchor } ) ) {
  145. 		my $index = 0;
  146. 		$index++ until $cmds[$index] eq $cmd or $index == @cmds;
  147. 		splice( @cmds, $index, 1 );
  148. 	}
  149. }
  150.  
  151. # Write the help to a HTML file
  152. my $htmlhelp = &HTMLHead( );
  153. $htmlhelp .= &HTMLList( );
  154. foreach my $cmd ( @cmds ) {
  155. 	$htmlhelp .= &HTMLCommand( $cmd );
  156. }
  157. $htmlhelp .= &HTMLFoot( );
  158. open( HTML, ">", $outfile ) or die( "Error writing HTML to file \"$outfile\"." );
  159. print HTML $htmlhelp;
  160. close( HTML );
  161.  
  162. # Open the newly created HTML file in the default browser (may generate warning messages with Firefox)
  163. if ( `which sensible-browser` ) {
  164. 	exec( 'sensible-browser', $outfile );
  165. } elsif ( `which xdg-open > /dev/null` ) {
  166. 	exec( 'xdg-open', $outfile );
  167. } elsif ( `which gnome-open > /dev/null` ) {
  168. 	exec( 'gnome-open', $outfile );
  169. } elsif ( `which x-www-browser` ) {
  170. 	exec( 'x-www-browser', $outfile );
  171. } else {
  172. 	my $browser = `gconftool -g /desktop/gnome/url-handlers/http/command 2> /dev/null`;
  173. 	if ( $browser ) {
  174. 		exec( $browser, $outfile );
  175. 	} else {
  176. 		die "Unable to locate default browser; open \"$outfile\" manually.";
  177. 	}
  178. }
  179.  
  180.  
  181.  
  182.  
  183. sub Alphabet( ) {
  184. 	my $html = "<table class=\"Alphabet\">\n<tr>\n";
  185. 	my $found = 0;
  186. 	foreach my $c ( @cmds ) {
  187. 		my $A = uc( substr( $c, 0, 1 ) );
  188. 		if ( $A !~ /[A-Z]/ ) {
  189. 			$found = 1;
  190. 		}
  191. 	}
  192. 	if ( $found ) {
  193. 		$html .= "\t<th><a href=\"#Punc\">#</a></th>\n";
  194. 	} else {
  195. 		$html .= "\t<th style=\"color: gray;\">#</th>\n";
  196. 	}
  197. 	foreach my $a ( 'a' .. 'z' ) {
  198. 		my $A = uc( $a );
  199. 		my $found = 0;
  200. 		foreach my $c ( @cmds ) {
  201. 			if ( lc( substr( $c, 0, 1 ) ) eq $a ) {
  202. 				$found = 1;
  203. 			}
  204. 		}
  205. 		if ( $found ) {
  206. 			$html .= "\t<th><a href=\"#$A\">$A</a></th>\n";
  207. 		} else {
  208. 			$html .= "\t<th style=\"color: gray;\">$A</th>\n";
  209. 		}
  210. 	}
  211. 	$html .= "</tr>\n</table>\n";
  212. 	return $html;
  213. }
  214.  
  215.  
  216. sub Anchor( ) {
  217. 	my $cmd = $_[0];
  218. 	my $firstchar = substr( $cmd, 0, 1 );
  219. 	my $anchor = $cmd;
  220. 	if ( $firstchar eq "." ) { $anchor = "dot"; }
  221. 	if ( $firstchar eq ":" ) { $anchor = "colon"; }
  222. 	if ( $firstchar eq '!' ) { $anchor = "exclamation"; }
  223. 	if ( $firstchar eq "(" ) { $anchor = "parentheses"; }
  224. 	if ( $firstchar eq "[" ) { $anchor = "brackets"; }
  225. 	if ( $firstchar eq "{" ) { $anchor = "braces"; }
  226. 	return $anchor;
  227. }
  228.  
  229.  
  230. sub HTMLCommand( ) {
  231. 	my $cmd = $_[0];
  232. 	my $anchor = &Anchor( $cmd );
  233. 	my $type;
  234. 	my $class;
  235. 	if ( grep { $_ eq $cmd } @coreutils ) {
  236. 		$class = 'CoreUtils';
  237. 		$type = "<p><strong>coreutils</strong></p>\n\n";
  238. 	} elsif ( grep { $_ eq $cmd } @builtins ) {
  239. 		$class = 'BuiltIn';
  240. 		$type = "<p><strong>builtin command</strong></p>\n\n";
  241. 	} elsif ( grep { $_ eq $cmd } @reserved ) {
  242. 		$class = 'ReservedWord';
  243. 		$type = "<p><strong>reserved word</strong></p>\n\n";
  244. 	} else {
  245. 		$class = '';
  246. 		$type = '';
  247. 	}
  248. 	my $html = '';
  249. 	if ( $class ne '' ) {
  250. 		$html .= "<div class=\"$class\">\n\n";
  251. 	}
  252. 	$html .= "<h2 id=\"$anchor\">$cmd</h2>\n\n$type<pre>";
  253. 	$html .= escapeHTML( $helplong{ $anchor } );
  254. 	$html .= "</pre>\n\n<div class=\"Center\"><a href=\"#\">Back to the top of this page</a></div>\n\n<p>&nbsp;</p>\n\n";
  255. 	if ( $class ne '' ) {
  256. 		$html .= "</div>\n\n";
  257. 	}
  258. 	return $html;
  259. }
  260.  
  261.  
  262. sub HTMLFoot( ) {
  263. 	my @now = localtime( );
  264. 	my $html = "<table>\n<tr id=\"Note\">\n\t<td class=\"Bold Top\">Note:</td>\n\t<td>&nbsp;</td>\n";
  265. 	$html .= "\t<td>Not all reserved words are listed here, only the ones for which help is available.</td>\n</tr>\n</table>\n\n";
  266. 	$html .= "<p>&nbsp;</p>\n\n<div class=\"Center\">\n\n<p>This HTML help was generated on ";
  267. 	$html .= sprintf( "%4d-%02d-%02d", $now[5] + 1900, $now[4], $now[3] );
  268. 	$html .= " by <a href=\"http://www.robvanderwoude.com/perlexamples.php#allhelp\">";
  269. 	$html .= "allhelp.pl</a>, Version $scriptver<br />\n";
  270. 	$html .= "Written by Rob van der Woude<br />\n";
  271. 	$html .= "<a href=\"http://www.robvanderwoude.com/\">http://www.robvanderwoude.com</a></p>\n\n";
  272. 	$html .= "</div>\n\n</div>\n\n</div>\n\n<p>&nbsp;</p>\n\n</body>\n</html>";
  273. }
  274.  
  275.  
  276. sub HTMLHead( ) {
  277. 	my $title = &LinuxVer( );
  278. 	my $html = <<"END_OF_HTML";
  279. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  280. <html lang="en">
  281. <head>
  282. <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7;FF=3;OtherUA=4">
  283. <meta name="robots" content="index,follow">
  284. <meta name="generator" content="allhelp.pl, Version $scriptver, by Rob van der Woude, www.robvanderwoude.com">
  285. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  286. <meta http-equiv="Content-Style-Type" content="text/css">
  287.  
  288. <title>Help for $title</title>
  289.  
  290. <style type="text/css">
  291. a, a.visited
  292. {
  293. 	color: blue;
  294. }
  295.  
  296. td.Command
  297. {
  298. 	vertical-align: top;
  299. 	padding-left: 10px;
  300. 	padding-right: 5px;
  301. 	font-weight: bold;
  302. 	white-space: nowrap;
  303. }
  304.  
  305. th
  306. {
  307. 	vertical-align: top;
  308. }
  309.  
  310. table.Alphabet
  311. {
  312. 	border: 2px solid blue;
  313. 	margin: 0 auto 0 auto;
  314. 	text-align: center;
  315. 	vertical-align: middle;
  316. 	width: 100%;
  317. }
  318.  
  319. table.Alphabet th
  320. {
  321. 	padding: 5px;
  322. 	width: 4%;
  323. }
  324.  
  325. table.List
  326. {
  327. 	margin: 0 auto 0 auto;
  328. 	width: 100%;
  329. }
  330.  
  331. table.List th
  332. {
  333. 	background-color: blue;
  334. 	color: white;
  335. 	font-size: 120%;
  336. 	font-weight: bold;
  337. 	padding-left: 10px;
  338. }
  339.  
  340. pre
  341. {
  342. 	white-space: pre-wrap;
  343. }
  344.  
  345. .Bold
  346. {
  347. 	font-weight: bold;
  348. }
  349.  
  350. .Center
  351. {
  352. 	text-align: center;
  353. 	margin-left: auto;
  354. 	margin-right: auto;
  355. }
  356.  
  357. .Left
  358. {
  359. 	text-align: left;
  360. }
  361.  
  362. .Smallfont
  363. {
  364. 	font-size: 60%;
  365. }
  366.  
  367. .Top
  368. {
  369. 	vertical-align: top;
  370. }
  371. </style>
  372.  
  373. </head>
  374. <body>
  375.  
  376. <h2 class="Center">Help for</h2>
  377.  
  378. <h1 class="Center">CoreUtils, internal Bash commands</h1>
  379.  
  380. <h2 class="Center">and reserved words&nbsp;<sup>(<a href="#Note">*</a>)</sup></h2>
  381.  
  382. <h3 class="Center">$title</h3>
  383.  
  384. <p>&nbsp;</p>
  385.  
  386. <div class="Center" style="width: 50em;">
  387.  
  388. <div class="Left" style="width: 50em;">
  389.  
  390. END_OF_HTML
  391.  
  392. 	$html .= Alphabet( );
  393. 	return $html;
  394. }
  395.  
  396.  
  397. sub HTMLList( ) {
  398. 	my $lastfirstchar = '';
  399. 	my $html = "<table class=\"List\">\n";
  400. 	$html .= "<tr id=\"Punc\">\n\t<th colspan=\"2\">Punctuation</th>\n</tr>\n";
  401. 	$html .= "<tr>\n\t<td colspan=\"2\">&nbsp;</td>\n</tr>\n";
  402. 	foreach my $cmd ( @cmds ) {
  403. 		my $firstchar = '';
  404. 		if ( "$cmd" =~ m/^[a-z]/ ) {
  405. 			"$cmd" =~ /^([a-z])/;
  406. 			$firstchar = uc( $1 );
  407. 			if ( $firstchar ) {
  408. 				if ( $firstchar ne $lastfirstchar ) {
  409. 					$html .= "<tr>\n\t<td colspan=\"2\">&nbsp;</td>\n</tr>\n";
  410. 					$html .= "<tr id=\"$firstchar\">\n\t<th colspan=\"2\">$firstchar</th>\n</tr>\n";
  411. 					$html .= "<tr>\n\t<td colspan=\"2\">&nbsp;</td>\n</tr>\n";
  412. 				}
  413. 			}
  414. 		}
  415. 		$lastfirstchar = $firstchar;
  416. 		my $anchor = &Anchor( $cmd );
  417. 		my $help = escapeHTML( $helpshort{ $anchor } );
  418. 		my $class;
  419. 		if ( grep { $_ eq $cmd } @coreutils ) {
  420. 			$class = ' class="CoreUtils"';
  421. 		} elsif ( grep { $_ eq $anchor } @builtins ) {
  422. 			$class = ' class="BuiltIn"';
  423. 		} elsif ( grep { $_ eq $anchor } @reserved ) {
  424. 			$class = ' class="ReservedWord"';
  425. 		} else {
  426. 			$class = '';
  427. 		}
  428. 		$help =~ s/[\t ]+/ /g;
  429. 		$html .= "<tr$class>\n\t<td class=\"Command\"><a href=\"#$anchor\">$cmd</a></td>\n\t<td>$help</td>\n</tr>\n";
  430. 	}
  431. 	$html .= "</table>\n\n<p>&nbsp;</p>\n\n";
  432. 	return $html;
  433. }
  434.  
  435.  
  436. sub LinuxVer( ) {
  437. 	my $os = '';
  438. 	open( SHELL, "-|", "bash", "-c", "uname -sirv" );
  439. 	while( <SHELL> ) {
  440. 		chomp( $os = $_ );
  441. 	}
  442. 	close( SHELL );
  443. 	if ( $os eq '' ) {
  444. 		$os = "$Config{osname} $Config{osvers}";
  445. 	}
  446. 	return $os;
  447. }
  448.  

page last uploaded: 2016-12-15, 11:20