#!/bin/sh #< Convert a shell script into HTML, with syntax highlighting # # (C) 2004 Kevin Waldron # Released under the terms of the GNU General Public Licence # # Most modern Bourne Shell features are implemented here. Other # common external commands are also implemented. We can't implement # everything that may exist in everyones PATH's however!! if [ "$#" -ne "2" ]; then echo "Usage: $(basename $0) filename outputfile" && exit 1 fi O_FILE=$2 if [ -e "${O_FILE}" ]; then echo "$(basename $0): Error: ${O_FILE} already exists" && exit 1 fi I_FILE=$1 if [ ! -e "${I_FILE}" ]; then echo "$(basename $0): Error: ${I_FILE} does not exist" && exit 1 fi # Print standard header stuff to file #echo "" >> ${O_FILE} #echo "" >> ${O_FILE} #echo "" >> ${O_FILE} #echo "$(basename ${I_FILE})" >> ${O_FILE} #echo "" >> ${O_FILE} #echo "" >> ${O_FILE} echo "
" >> ${O_FILE}

# main awk routine - syntax highlighting done here!
awk '{
    # these gsubs globally replace special chars
    gsub( "&", "\\&", $0 );
    gsub( "<", "\\<", $0 );
    gsub( ">", "\\>", $0 );


          commandArray[0] = "awk";
	  commandArray[1] = "read";
	  commandArray[2] = "exit";
	  commandArray[3] = "ls";
	  commandArray[4] = "rm";
	  commandArray[5] = "sort";
	  commandArray[6] = "uniq";
	  commandArray[7] = "sed";
	  commandArray[8] = "mv";
	  commandArray[9] = "cp";
	  commandArray[10] = "join";
	  commandArray[11] = "grep";
	  commandArray[12] = "cat";
	  commandArray[13] = "df";
	  commandArray[14] = "cd";
	  commandArray[15] = "basename";
	  commandArray[16] = "id";
	  commandArray[17] = "tr";
	  commandArray[18] = "ls";
	  commandArray[19] = "true";
	  commandArray[20] = "false";
	  commandArray[21] = "seq";
	  commandArray[22] = "cut";
	  commandArray[23] = "getopt";
	  commandArray[24] = "getopts";
	  commandArray[25] = "gunzip";
	  commandArray[26] = "gzip";
	  commandArray[27] = "tar";
	  commandArray[28] = "date";
	  commandArray[29] = "clear";
	  commandArray[30] = "ps";
	  commandArray[31] = "ifconfig";
	  commandArray[32] = "ping";
	  commandArray[33] = "tput";
	  commandArray[34] = "useradd";
	  commandArray[35] = "passwd";
	  commandArray[36] = "stty";
	  commandArray[37] = "chown";
	  commandArray[38] = "chmod";
	  commandArray[39] = "trap";
	  commandArray[40] = "sleep";
	  commandArray[41] = "wait";
	  commandArray[42] = "last";
	  commandArray[43] = "head";
	  commandArray[44] = "let";
	  commandArray[45] = "shift";
	  commandArray[46] = "unalias";
	  commandArray[47] = "read";
	  commandArray[48] = "unset";
	  commandArray[49] = "alias";
	  commandArray[50] = "expr";
	  commandArray[51] = "printf";
	  commandArray[52] = "mkdir";
	  commandArray[53] = "declare";
	  commandArray[54] = "local";
	  commandArray[55] = "tail";
      commandArray[56] = "hostname";
	  commandArray[57] = "xterm";
	  commandArray[58] = "bc";
	  commandArray[59] = "wc";
	  commandArray[60] = "more";
	  commandArray[61] = "find";
	  commandArray[62] = "mount";
	  commandArray[63] = "who";
	  commandArray[64] = "suspend";
	  commandArray[65] = "ulimit";
	  commandArray[66] = "umask";
	  commandArray[67] = "source";
	  commandArray[68] = "bind";
	  commandArray[69] = "builtin";
	  commandArray[70] = "typeset";
	  commandArray[71] = "export";
	  commandArray[72] = "fc";
	  commandArray[73] = "history";
	  commandArray[74] = "hash";
	  commandArray[75] = "jobs";
	  commandArray[76] = "kill";
	  commandArray[77] = "fg";
	  commandArray[78] = "bg";
	  commandArray[79] = "logout";
	  commandArray[80] = "popd";
	  commandArray[81] = "pushd";
	  commandArray[82] = "pwd";
	  commandArray[83] = "shopt";
	  commandArray[84] = "test";
	  commandArray[85] = "touch";

      # update array_length manually below!
	  array_length = 85;

    # deal with comments first - ignore entire line if one is found
    if ( $0 ~ /^[ 	]*#/ ) {
         print ""$0"";
    }
    else {
       # syntax highlight on a line-by-line, element-by-element basis
       # dealing with echo firstly, so we can say echo "echo if else"
       # and only have the "echo" highlighted
       if ( $0 ~ /^[ 	]*echo/ ) {
          gsub( /^[ 	]*echo/, "&", $0 );
          gsub( /;[ 	]*echo/, "; echo", $0 );

          # check for commands within ` and ( in echo
          for ( i = 0; i <= array_length; i++ ) {
	     x=commandArray[i];

	     if ( $0 ~ x ) {
	         reg = "[(]"x"[ 	]*";
		 gsub( reg, "("x" ", $0 );
		 reg = "[(][ ]+"x"[ 	]+";
		 gsub( reg, "( "x" ", $0 );
		 reg = "[`]"x"[ 	]*";
		 gsub( reg, "`"x" ", $0 );
		 reg = "[`][ ]+"x"[ 	]+";
		 gsub( reg, "` "x" ", $0 );
		 reg = "^[ 	]*"x"[ 	]*$";
		 gsub( reg, "&", $0 );
		 reg = "[ ]+"x"[ 	]+";
		 gsub( reg, "&", $0 );
	     }
	  }
       }
       else {
          # catch other echos - i.e. with case
          gsub( /[ 	]*echo[ 	]+/, "&", $0 );

          # if - will be at start of line (usually)
          gsub( /if test/,
                "if test", $0 );
	      gsub( /^[ 	]*if[ 	]+/,
                "&", $0 );
	      gsub( /^[ 	]*if[ 	]*$/,
                "&", $0 );

          # else - will be at start of line (usually)
          gsub( /^[ 	]*else[ 	]*$/,
                "&", $0 );

          # elif - will be at start of line (usually)
          gsub( /^[ 	]*elif[ 	]+/,
                "&", $0 );

          # fi - will also usually be at the start of a line
          gsub( /^[ 	]*fi[ 	]*$/,
                "&", $0 );

          # for - will be at start of line (usually)
          gsub( /^[ 	]*for[ 	]+/,
                "&", $0 );

          # select - will be at start of line (usually)
          gsub( /^[ 	]*select[ 	]+/,
                "&", $0 );

          # while - will be at start of line (usually)
          gsub( /while read/,
	        "while read", $0 );
	      gsub( /^[ 	]*while[ 	]+/,
                "&", $0 );

          # until - will be at start of line (usually)
          gsub( /^[ 	]*until[ 	]+/,
                "&", $0 );

          # case - will be at start of line (usually)
          gsub( /^[ 	]*case[ 	]+/,
                "&", $0 );

          # esac - will be at start of line (usually)
          gsub( /^[ 	]*esac[ 	]*$/,
                "&", $0 );

          # function - will be at start of line (usually)
          gsub( /^[ 	]*function[ 	]+/,
                "&", $0 );

          # done - will be at start of line (usually)
          gsub( /^[ 	]*done[ 	]*/,
                "&", $0 );

          # then - can be at start of line, or after a ;
          gsub( /^[ 	]*then[ 	]*$/,
                "&", $0 );
          gsub( /;[ 	]*then[ 	]*$/,
                "; then", $0 );

          # special case - then followed by comment
          if ( /[ 	]*then[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /then/,
                   "&", $0 );
          }

          # special case - do followed by comment
          if ( /[ 	]*do[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /do/,
                   "&", $0 );
          }

	      # special case - else followed by comment
          if ( /[ 	]*else[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /else/,
                   "&", $0 );
          }

	      # special case - break followed by comment
          if ( /[ 	]*break[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /break/,
                   "&", $0 );
          }

	      # special case - continue followed by comment
          if ( /[ 	]*continue[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /continue/,
                   "&", $0 );
          }

	      # special case - done followed by comment
          if ( /[ 	]*done[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /done/,
                   "&", $0 );
          }

	      # special case - fi followed by comment
          if ( /[ 	]*fi[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /fi/,
                   "&", $0 );
          }

	      # special case - esac followed by comment
          if ( /[ 	]*esac[ 	]*#/ ) {
               gsub( /[^$]#.*$/,
                   "&", $0 );
               gsub( /esac/,
                   "&", $0 );
          }

          # do - can be at start of line, or after a ;
          gsub( /^[ 	]*do[ 	]*$/,
                "&", $0 );
          gsub( /;[ 	]*do[ 	]*$/,
                "; do", $0 );

	      # continue - can be at start of line, or after a ;
          gsub( /^[ 	]*continue[ 	]*$/,
                "&", $0 );
          gsub( /;[ 	]*continue[ 	]*$/,
                "; continue", $0 );
	      gsub( /continue;/,
                "continue;", $0 );

	      # break - can be at start of line, or after a ; or ending in ;
          gsub( /^[ 	]*break[ 	]*$/,
                "&", $0 );
          gsub( /;[ 	]*break[ 	]*$/,
                "; break", $0 );
	      gsub( /break[ ]*;/,
                "break ;", $0 );

	      # return - can be at start of line, or after a ;
          gsub( /^[ 	]*return[ 	]*/,
                "&", $0 );
          gsub( /;[ 	]*return[ 	]*/,
                "; return", $0 );

	      # scan for more comments - probably makes some of the code
          # above redundant! A bit of a "catch all" for comments that
          # slip through the net.
          if ( /[^${#]#[^#]/ ) {
             gsub( /[^$^]#.*$/,
                 "&", $0 );
          }

	      # exec - special case as more commands may follow it
	      if ( /[^#][	]*exec[		]*/ ) {
	         gsub( /exec/, "&", $0 );
	      }
          if ( /^exec/ ) { gsub ( /exec/, "exec", $0 ); }


	      # eval - special case as more commands may follow it
	      if ( /[^#][	]*eval[		]*/ ) {
	         gsub( /eval/, "&", $0 );
	      }

	      # set - to allow tput reset
	      if ( /set/ ) {
	         gsub( /^[	]*set/, "&", $0 );
	      }

	  for ( i = 0; i <= array_length; i++ ) {
	     x=commandArray[i];

	     if ( $0 ~ x ) {
	         reg = "[(]"x"[ 	]*";
		 gsub( reg, "("x" ", $0 );
		 reg = "[(][ ]+"x"[ 	]+";
		 gsub( reg, "( "x" ", $0 );
		 reg = "[`]"x"[ 	]*";
		 gsub( reg, "`"x" ", $0 );
		 reg = "[\047]"x"[ 	]*";
		 gsub( reg, "\047"x" ", $0 );
		 reg = "[\042]"x"[ 	]*";
		 gsub( reg, "\042"x" ", $0 );
		 reg = "[`][ ]+"x"[ 	]+";
		 gsub( reg, "` "x" ", $0 );
		 reg = "[ 	]+"x"[ 	]+";
		 gsub( reg, "&", $0 );
		 reg = x";";
		 gsub( reg, ""x";", $0 );
		 reg = "^[ 	]*"x"[ 	]+";
		 gsub( reg, "&", $0 );
		 reg = "[ ]*"x"[`]";
		 gsub( reg, " "x"`", $0 );
		 reg = "[ ]*"x"[)]";
		 gsub( reg, " "x")", $0 );
		 reg = "[ ]*"x"[ ]+[`]";
		 gsub( reg, " "x" `", $0 );
		 reg = "[ ]*"x"[ ]+[)]";
		 gsub( reg, " "x" )", $0 );
		 reg = "^[ 	]*"x"[ 	]*$";
		 gsub( reg, "&", $0 );
		 reg = "[|][ ]+"x;
		 gsub( reg, "| "x"", $0 );
	     }
	  }

          # some comparison ops
          gsub( /[ 	]+\-gt[ 	]+/, " -gt ", $0 );
          gsub( /[ 	]+\-lt[ 	]+/, " -lt ", $0 );
          gsub( /[ 	]+\-eq[ 	]+/, " -eq ", $0 );
          gsub( /[ 	]+\-ne[ 	]+/, " -ne ", $0 );
          gsub( /[ 	]+\-ge[ 	]+/, " -ge ", $0 );
          gsub( /[ 	]+\-le[ 	]+/, " -le ", $0 );
          gsub( /[ 	]+\-a[ 	]+/, " -a ", $0 );
          gsub( /[ 	]+\-o[ 	]+/, " -o ", $0 );
	      gsub( /[ 	]+\-n[ 	]+/, " -n ", $0 );
          gsub( /[ 	]+\![ 	]+/, " ! ", $0 );
          gsub( /[ 	]+\-e[ 	]+/, " -e ", $0 );
          gsub( /[ 	]+\-z[ 	]+/, " -z ", $0 );
          gsub( /[ 	]+\-f[ 	]+/, " -f ", $0 );
       }
       # print out the line now we are all gsubbed
       print $0
    }
}' ${I_FILE} >> ${O_FILE}

# print website plug - please leave in to "spread the word"
echo "

" >> ${O_FILE} echo "# Generated with sh2html - freely available from http://www.zazzybob.com/sh2html.html" >> ${O_FILE} # print standard footer stuff to file echo "
" >> ${O_FILE} #echo "" >> ${O_FILE} #echo "" >> ${O_FILE} exit 0