#!/usr/bin/ksh93 ################################################################ function usagemsg_menugen { print " Program: menugen Create naviation and look-and-feel characteristics for a directory of web content files. Usage: menugen [-g]] [-S]] [-u]] [-f datafile]] | -c | -C | -h -c = Create a default \"menugen.cfg\" file -C = Overwrite \"menugen.cfg\" file, even if it already exists -g = Show grandchild links in menus -R = Position menu bar on Right side of page -S = If the static menu bar exists, overwrite it with the default -f = Use data file specified by value \"datafile\" -u = Underline Menu Links -n = Generate .html files -v = Verbose mode -V = Very Verbose mode -h = Display help file Author: Dana French (dfrench@mtxia.com) Copyright 2005 \"Autocontent Enabled\" " } ################################################################ #### #### Description #### #### "menugen" is a shell script that provides the ability to #### easily maintain and modify web based documentation. #### This script creates a standard "look-and-feel" for user #### supplied HTML based content, and generates navigation #### links between the pages. An web server feature called #### "Server Side Includes" (SSI) is utilized by "menugen" to #### reference the various parts and pieces of each page. #### #### To use "menugen", the user should create content and #### store it in files called "XXXXXXXX.content.shtml", where #### XXXXXXXX is some prefix file name defined by the user. #### "menugen" creates menus, links, headers, titles, #### footers, contact info links, etc, based on information #### stored in a user defined relationship file. The #### relationship file is assumed to be in the same directory #### with the "XXXXXXXX.content.shtml" files and is called #### "menugen.dat". #### #### "menugen" allows users to modify the "look-and-feel" of #### all files in a directory by storing configuration #### information such as colors, font sizes, title info, etc #### in a file called "menugen.cfg". #### #### The "-c" option will create a file called "menugen.cfg" #### if it does not already exist. If it does exist it will #### not overwrite it. To recreate the "menugen.cfg" file, #### you will first have to remove it. The "menugen.cfg" #### file contains user modifiable parameters such as font #### colors, font sizes background color, title and contact #### information. #### #### One of the values defined in the "menugen.cfg" file is #### called "THEME". This is a title which is displayed at #### the top of every page. The title can be a two part #### title separated by a colon (:). The part of the title #### to the left of the colon will be displayed in a larger #### text. The part of the title to the right of the colon #### will be displayed in italics and a smaller text. All #### values in the configuration file may be changed to suit #### the users particular needs. The "menugen.cfg" file MUST #### be executeable. #### #### The "menugen" program creates a menu file for each page #### which contains the relationships between each page, its #### parent page, and its child pages. The links displayed #### on the menu by default are that of the parent and #### children of each page. The "-g" option causes the #### grandchildren of each page to also be included in the #### menu. #### #### Normally, if the static menu bar file exists, it is not #### overwritten in order to preserve any user customization #### of that file. However the "-S" option will cause the #### static menubar file to be overwritten with the default #### values. The static menu bar file is "staticbar.shtml". #### #### The datafile describes the relationships between all the #### web pages in the current directory. The relationship #### between the pages is maintained via parent/child #### references. By default the relationships are read from #### a file called "menugen.dat" in the current directory. #### The "-f" option allows the user to specify a different #### file name. The datafile has the following format: #### #### PARENTCURRENTSHORT DESCRIPTION #### #### PARENT and CURRENT are file name prefixes and are #### usually limited to 8 characters or less. TAB characters #### between the fields is mandatory. PARENT is the parent #### of the CURRENT page. The SHORT DESCRIPTION is a #### description of the CURRENT page. An example of datafile #### would be: #### #### NULL index Home Page #### index child1 Child 1 of index #### index child2 Child 2 of index #### index child3 Child 3 of index #### child1 child11 Child 1 of child1 #### child1 child12 Child 2 of child1 #### child1 child13 Child 3 of child1 #### child1 child14 Child 4 of child1 #### child2 child21 Child 1 of child2 #### child2 child22 Child 2 of child2 #### child2 child23 Child 3 of child2 #### child3 child31 Child 1 of child3 #### child3 child32 Child 2 of child3 #### #### In this example, the page "index" has three child pages #### called "child1", "child2", and "child3". The menu on #### the "index" page would reference these three pages. The #### page "child1" has four child pages called "child11", #### "child12", "child13", "child14". The menu on the #### "child1" page would reference these four pages. And so #### on for child pages "child2" and "child3". #### #### The "-h" option displays this help file and is assumed #### to reside in the file called #### "/usr/local/sh/README.menugen". #### #### Most graphical web browsers will show hypertext links as #### underlined text of a different color than normal text. #### When this program creates the menu bars, the links are #### configured NOT to have underlines. If you want #### #### the links in the menu bars to have underlines, use the #### "-u" option. #### #### Assumptions: #### #### It is assumed that a file exists which describes a #### parent-child relationship for each document. The format #### of this file assumes the first column contains the #### prefix name of the parent document, the second column #### contains the prefix name of the child document, and the #### third column contains a very short description (16 char or #### less), of the child document. #### #### The "content" files are assumed to be in the same #### directory as the "menugen.dat" file. #### #### Dependencies: #### #### This script requires a "menugen.dat" file be created by #### the user, which is normally a manual process, however #### can be automated depending upon desired usage. #### #### Products: #### #### This script generates various parts and pieces #### comprising the look-and-feel of the web pages. This #### includes a title (title.shtml), header (X.shtml), footer #### (footer.shtml), dynamic navigation links (X.menu.shtml), #### static navigation links (staticbar.shtml), and a #### configuration file (menugen.cfg). "X" in the above file #### names represents the filename prefix of each page #### identified in the "menugen.dat" file. #### #### Configured Usage: #### #### This script is written to be used as a command line #### program, but can be scheduled to run through cron or any #### other scheduling system. If scheduled, the current #### directory must be the same as the directory containing #### the "menugen.dat" file. #### #### Details: ################################################################ ################################################################ #### #### #### The "mkconfig" function checks for or creates a #### configuration file for the "menugen" program. This #### configuration file contains several parameter settings #### that control text, color, font, sizes, etc. #### #### If the "menugen" configuration file already exists, do not #### overwrite it, simply return with a non-zero exit code. #### If the "menugen" configuration file does not exist, #### create it and exit with a zero exit code. #### ################################################################ mkconfig() { if [[ -f "./menugen.cfg" ]] then print "\"menugen.cfg\" file already exists, not overwritten" return 1 fi print "THEME=\"Default Theme: Default Subtheme\" # Title displayed at top of every page" > ./menugen.cfg print "CLR_TEXT=\"#000000\" # Text color (default=#000000)" >> ./menugen.cfg print "CLR_BACKGRD=\"#FFFFFF\" # Background color (default=#FFFFFF)" >> ./menugen.cfg print "CLR_LINK=\"#0000FF\" # Link color (default=#0000FF)" >> ./menugen.cfg print "CLR_ALINK=\"#777700\" # Active Link color (default=#777700)" >> ./menugen.cfg print "CLR_VLINK=\"#770000\" # Viewed Link color (default=#770000)" >> ./menugen.cfg print "CLR_MENUBORDER=\"#ABADC9\" # Menu Border color (default=#ABADC9)" >> ./menugen.cfg print "CLR_MENUBG=\"#DDDDDD\" # Menu Background color (default=#DDDDDD)" >> ./menugen.cfg print "CLR_MENUTEXT=\"#000000\" # Menu Text color (default=#000000)" >> ./menugen.cfg print "SIZ_BASEFONT=\"4\" # Base Font Size (default=4)" >> ./menugen.cfg print "CONTACT_NAME=\"Dana French\" # Person responsible for this Page (default=Dana French)" >> ./menugen.cfg print "CONTACT_EMAIL=\"dfrench@mtxia.com\" # Email address of person responsible for this page (default=dfrench@mtxia.com)" >> ./menugen.cfg chmod 755 ./menugen.cfg print "\"menugen.cfg\" file was created in the current directory." return 0 } ################################################################ #### #### The "mg_footer" function outputs the "footer" section of #### the HTML pages, containing the information from the #### "configuration" file. #### ################################################################ mg_footer() { print "

For information regarding this page, contact ${CONTACT_NAME} ( ${CONTACT_EMAIL} )

" } ################################################################ #### #### The "mg_hr" function outputs the "horizontal rule" #### section of the HTML pages, using the parameter settings #### from the "configuration" file. #### ################################################################ mg_hr() { print "
 
" } ################################################################ #### #### The "mg_staticbar" function outputs the "static menu #### bar" section of the HTML pages, using the parameter #### settings from the "configuration" file. Currently this #### section appears at the top of each HTML page. #### ################################################################ mg_staticbar() { print " " #### #### If the "underline" option was specified on the command #### line, output a style tag to cause HTML links in the static #### menu bar to be underlined. #### if (( UNDERLINE == TRUE )) then print " " fi #### #### Output the "static menu bar" containing a static set of #### HTML links. This program generates a hardcoded set of #### links and does not currently read these from the #### configuration file. This will be a future enhancement. #### print "

HCA | GGI | Mt Xia

" #### #### If the "underline" option was specified on the command #### line, output a style tag to cause HTML links in the menu #### bar to be turned off. #### if (( UNDERLINE == TRUE )) then print " " fi print " " } ################################################################ #### #### The "mg_titlebar" function outputs the "title bar" #### section of the HTML pages, using parameter settings from #### the "configuration" file. If the "THEME" parameter #### contains a colon character (:), the value is split into #### two parts using the colon character as a delimiter. The #### first part of the THEME value is displayed in a larger #### text than the second part. #### ################################################################ mg_titlebar() { THEME1="${THEME}" THEME2=" " if [[ "_${THEME}" == _*:* ]] then THEME1="${THEME%%:*}" THEME2="${THEME#*:}" fi print "


${THEME1}:
${THEME2}

" } ################################################################ #### #### The "cat_file" function reads a file specifed by the #### first command line argument to this function, and #### outputs the content of the file to standard output. #### This is similar to the Unix "cat" command. the purpose #### of this function is to avoid executing the external Unix #### command "cat". #### ################################################################ cat_file() { if [[ -s "${1}" ]] then while IFS=$'\n' read -r -- DATALINE do print -r -- "${DATALINE}" done < "${1}" else print -u 2 "# WARNING: ${1} does not exist" fi } ################################################################ #### #### The "menugen" function is the main portion of this #### program. It generates the various parts and pieces of #### each web page based on a parent-child relationship #### specified in a datafile. This datafile contains the #### file name prefix of each file to be processed by this #### program. #### ################################################################ function menugen { VERSION="10.0" TRUE="1" FALSE="0" EXITCODE="0" VERBOSE="${FALSE}" VERYVERB="${FALSE}" DATAFILE="./menugen.dat" GRANDCHILD="${FALSE}" HTMLFILES="${FALSE}" UNDERLINE="${FALSE}" MENUPOS="left" ################################################################ #### #### Check for the existance of the default configuration #### file and check to see that it is executable. If it is #### not executable, make it so. The default configuration #### file is always assumed to be in the current directory. #### After checking the existance and execute bit, execute #### the default configuration file for the purpose of #### establishing several shell variables that define #### look-and-feel parameters for colors, font sizes, etc. #### ################################################################ if [[ -s "./menugen.cfg" ]] then if [[ ! -x "./menugen.cfg" ]] then if ! chmod 755 "./menugen.cfg" then print "Unable to make \"menugen.cfg\" executable" return 6 fi fi . ./menugen.cfg fi ################################################################ #### #### For each of the standard parameter values in the default #### configuration file, check to see if the shell variable #### is unset or null. If so, assign the variable a default value. #### ################################################################ THEME="${THEME:-'Default Theme: Default Subtheme'}" CLR_TEXT="${CLR_TEXT:-'#000000'}" CLR_BACKGRD="${CLR_BACKGRD:-'#FFFFFF'}" CLR_LINK="${CLR_LINK:-'#0000FF'}" CLR_ALINK="${CLR_ALINK:-'#777700'}" CLR_VLINK="${CLR_VLINK:-'#770000'}" CLR_MENUBORDER="${CLR_MENUBORDER:-'#ABADC9'}" CLR_MENUBG="${CLR_MENUBG:-'#DDDDDD'}" CLR_MENUTEXT="${CLR_MENUTEXT:-'#000000'}" SIZ_BASEFONT="${SIZ_BASEFONT:-'4'}" CONTACT_NAME="${CONTACT_NAME:-'Dana French'}" CONTACT_EMAIL="${CONTACT_EMAIL:-'dfrench@mtxia.com'}" ################################################################ #### #### Define the default page data file that contains the #### parent-child relationships between pages. Also define #### several other parameter that control the default #### behavior of this script. #### ################################################################ while getopts ":vVcChgRSf:nu" OPTION do case "${OPTION}" in 'c') mkconfig return 3;; 'C') rm -f "./menugen.cfg"; mkconfig return 5;; 'h') usagemsg_menugen | more - "/usr/local/sh/README.menugen" return 4;; 'g') GRANDCHILD="${TRUE}";; 'R') MENUPOS="right";; 'S') rm -f "./staticbar.shtml";; 'f') DATAFILE="${OPTARG}";; 'n') HTMLFILES="${TRUE}";; 'u') UNDERLINE="${TRUE}";; 'v') VERBOSE="${TRUE}";; 'V') VERYVERB="${TRUE}";; '?') usagemsg_menugen "${0}" && return 1 ;; ':') usagemsg_menugen "${0}" && return 1 ;; esac done shift $(( ${OPTIND} - 1 )) trap "usagemsg_menugen ${0}" EXIT if [[ "_${DATAFILE}" = "_" || ! -s "${DATAFILE}" ]] then usagemsg_menugen "Invalid data file name" return 1 fi trap "-" EXIT ################################################################ (( VERBOSE == TRUE )) && print "# ${DATAFILE} will be used to define pages and relationships" (( VERBOSE == TRUE )) && (( GRANDCHILD == TRUE )) && print "# Grandchild links will be shown on menus" (( VERYVERB == TRUE )) && set -x #### #### Generate the static menu bar, title bar, horizontal #### rule, and page footer. Only generate the static menu #### bar if the file does not already exist. This is so the #### static menu bar can be modified without being #### overwritten each time the "menugen" program is executed. #### [[ ! -f "./staticbar.shtml" ]] && mg_staticbar > ./staticbar.shtml mg_titlebar > ./titlebar.shtml mg_hr > ./hr.shtml mg_footer > ./footer.shtml ################################################################ #### #### Read the parent-child relationship datafile and assign the #### values to shell variables. The data file should contain #### three fields, parent file name prefix, child file name #### prefix, and child file name description. The three #### fields should be delimited by "tab" characters. #### DATATMP0="/tmp/tmp0${$}.out" DATATMP1="/tmp/tmp1${$}.out" DATATMP2="/tmp/tmp2${$}.out" cat_file "${DATAFILE}" > "${DATATMP0}" while IFS=$' \t\n' read -r -- PARENTID1 PAGEID1 PAGENAME1 do (( VERBOSE == TRUE )) && print #### #### Based on the current value of the child file name #### prefix, re-read the entire datafile and extract only #### those lines whose parent file name prefix matches the #### current child file name prefix. This provides a list of #### children of the current child file name prefix. #### while IFS=$'\n' read -r -- DATALINE do [[ "${DATALINE}" == ${PAGEID1}+([$'b\t'])* ]] && print -r -- "${DATALINE}" done < "${DATATMP0}" > "${DATATMP1}" #### #### Based on the current value of the parent file name #### prefix, re-read the entire datafile and extract the #### first data line whose child file name prefix matches the #### current parent file name prefix. From this dataline, #### extract the description of the parent of the current #### child file name prefix and store this value in a shell #### variable. #### while IFS=$'\n' read -r -- DATALINE do if [[ "${DATALINE}" == *+([$'\t'])${PARENTID1}+([$'\t'])* ]] then DATALINE=${DATALINE//+([$'\t'])/:} PARENTNAME="${DATALINE##*:}" break fi done < "${DATATMP0}" (( VERBOSE == TRUE )) && print "# ${PARENTNAME}" typeset -u PGNMTMP="${PAGENAME1}" (( VERBOSE == TRUE )) && print "# ${PGNMTMP}" #### #### If the current data line begins with a comment character #### (#), skip it and continue with the next data line. #### if [[ "_${PARENTID1}" == _\#* ]] then continue fi #### #### If the "-R" command line option was specified, then #### create an "index.shtml" file that positions the "menu #### bar" on the right hand side of each HTML page. #### Otherwise generate an "index.shtml" file with the "menu #### bar" positioned on the left side of each HTML page. The #### "index.shtml" file is build assuming that server sides #### includes (SSI) is implemented on whatever web server #### will host these files. #### if [[ "_${MENUPOS}" = "_right" ]] then print " ${PAGENAME1} - ${THEME}

" > "${PAGEID1/#*\///tmp/}.shtml" else print " ${PAGENAME1} - ${THEME}

${PAGENAME1}


" > "${PAGEID1/#*\///tmp/}.shtml" fi ################################################################ #### #### Begin building the "menu bar" file. This will be unique #### to each HTML page and is based on the parent-child #### relationships defined in the datafile. #### print " " > "${PAGEID1/#*\///tmp/}.menu.shtml" #### #### If the "underline" option was specified on the command #### line, output a style tag to cause HTML links in the #### menu bar to be underlined. #### if (( UNDERLINE == TRUE )) then print " " >> "${PAGEID1/#*\///tmp/}.menu.shtml" fi #### #### Output the "menu bar" presentation to the menu bar file. #### print "

${PAGENAME1}


Current:${PAGENAME1// / }
Previous:${PARENTNAME// / } " >> "${PAGEID1/#*\///tmp/}.menu.shtml" #### #### If the description of the parent of the current child #### file name is equal to the phrase "Home Page", then #### output a link to the "index" file with a description of #### "Home Page". #### if [[ "_${PARENTNAME}" != "_Home Page" ]] then print "
Home Page" >> "${PAGEID1/#*\///tmp/}.menu.shtml" fi print "
" >> "${PAGEID1/#*\///tmp/}.menu.shtml" #### #### Using the previously generated list of children of the #### current child file name prefix, loop through each line #### in the list and extract the three fields into #### secondary shell #### variables. Again the three fields are parent file name #### prefix, child file name prefix, and child description. #### while IFS=$' \t\n' read -r -- PARENTID2 PAGEID2 PAGENAME2 do #### #### If the child file name prefix contains a hash mark (#) #### this means the link is a reference to an anchor tag #### within the same file. For this occurance, set a shell #### variable to the exact value of the child file name #### prefix. Otherwise set a shell variable to the child #### file name prefix followed by the literal characters #### ".shtml". LINK="${PAGEID2}.shtml" if [[ "_${PAGEID2}" == _*\#* ]] then LINK="${PAGEID2}" fi (( VERBOSE == TRUE )) && print " ${PAGENAME2}" #### #### Output the HTML link to the menu file. #### print "
${PAGENAME2// / }" >> "${PAGEID1/#*\///tmp/}.menu.shtml" if (( GRANDCHILD == TRUE )) then #### #### Re-read the parent-child relationship datafile and #### extract the lines that begin with the secondary child #### file name prefix and save the lines to a temporary #### storage file for processing. This data can be used for #### generating grandchild links, if so specified by command #### line option "-g". #### while IFS=$'\n' read -r -- DATALINE do [[ "_${DATALINE}" == _${PAGEID2}+([$'\t'])* ]] && print -r -- "${PAGEID2}" done < "${DATATMP0}" > "${DATATMP2}" #### #### Using the lines extracted from the parent-child #### relationship datafile that begin with the secondary #### child file name prefix, read each line and use the #### information to generate grandchild HTML links that will #### appear in the "menu" bar. These are grandchildren of #### the current child file name prefix. #### ICNT="${FALSE}" print "" >> "${PAGEID1/#*\///tmp/}.menu.shtml" while IFS=$' \t\n' read -r -- PARENTID3 PAGEID3 PAGENAME3 do ICNT="${TRUE}" LINK="${PAGEID3}.shtml" #### #### If the grandchild file name prefix contains a hash (#) #### character, then this page should link to an anchor tag #### associated with it's parent. #### if [[ "_${PAGEID3}" == _*\#* ]] then LINK="${PARENTID3}.shtml${PAGEID3}" fi print " ${PAGENAME3}" #### Display the grandchild link in the menu bar. print "
  • ${PAGENAME3// / }
  • " >> "${PAGEID1/#*\///tmp/}.menu.shtml" done < "${DATATMP2}" print "
    " >> "${PAGEID1}.menu.shtml" (( ICNT == TRUE )) && print "
    " >> "${PAGEID1/#*\///tmp/}.menu.shtml" fi done < "${DATATMP1}" ################################################################ print "

    " >> "${PAGEID1/#*\///tmp/}.menu.shtml" #### #### If the "underline" option was specified on the command #### line, output a style tag to cause HTML links in the menu #### bar to be turned off. #### if (( UNDERLINE == TRUE )) then print " " >> "${PAGEID1/#*\///tmp/}.menu.shtml" fi print " " >> "${PAGEID1/#*\///tmp/}.menu.shtml" ################################################################ #### #### If the "-R" option was specified on the command line, #### format the HTML to render the "menu" bar on the #### right hand side of the page, otherwise render the #### "menu" bar on the left hand side of the page. #### if [[ "_${MENUPOS}" = "_right" ]] then print "

    " >> "${PAGEID1/#*\///tmp/}.shtml" else print " " >> "${PAGEID1/#*\///tmp/}.shtml" fi print " " >> "${PAGEID1/#*\///tmp/}.shtml" #### #### If the "-n" option was specified on the command line, #### then in addition to generating SSI ".shtml" pages, also #### generate ".html" pages with all included pages inserted #### into the final document. #### if (( HTMLFILES == TRUE )) then print " ${PAGENAME1} - ${THEME} " > "${PAGEID1/#*\///tmp/}.html" #### #### Read the HTML code from the "staticbar.shtml" file and #### insert it into the ".html" file. Do the same for the #### "titlebar.shtml" and "hr.shtml" files. #### cat_file "staticbar.shtml" >> "${PAGEID1/#*\///tmp/}.html" cat_file "titlebar.shtml" >> "${PAGEID1/#*\///tmp/}.html" cat_file "hr.shtml" >> "${PAGEID1/#*\///tmp/}.html" #### #### If the "-R" option was specified on the command line, #### format the HTML to render the "menu" bar on the right #### hand side of the ".html" page, otherwise render the #### "menu" bar on the left hand side of the page. if [[ "_${MENUPOS}" = "_right" ]] then print "

    ${PAGENAME1}


    " >> "${PAGEID1}.html" # sed -e "s/\.shtml/.html/g" "${PAGEID1}.menu.shtml" >> "${PAGEID1/#*\///tmp/}.html" # replaced by following while loop #### Read the "menu" HTML code and insert it into the ".html" #### file. while IFS=$'\n' read -r -- DATALINE do print "${DATALINE//.shtml/.html}" done < "${PAGEID1}.menu.shtml" >> "${PAGEID1/#*\///tmp/}.html" print "
    " >> "${PAGEID1/#*\///tmp/}.html" #### Read the "content" file and insert it into the ".html" #### file. cat_file "${PAGEID1}.content.shtml" >> "${PAGEID1/#*\///tmp/}.html" print "

    " >> "${PAGEID1/#*\///tmp/}.html" else #### #### If the "-R" option was NOT specified on the command line, #### format the HTML to render the "menu" bar on the left #### hand side of the ".html" page. # sed -e "s/\.shtml/.html/g" "${PAGEID1}.menu.shtml" >> "${PAGEID1/#*\///tmp/}.html" # replaced by following while loop #### Read the "menu" file and insert it into the ".html" #### file. while IFS=$'\n' read -r -- DATALINE do print "${DATALINE//.shtml/.html}" done < "${PAGEID1}.menu.shtml" >> "${PAGEID1/#*\///tmp/}.html" #### Insert the page title into the ".html" file print "

    ${PAGENAME1}


    " >> "${PAGEID1/#*\///tmp/}.html" #### Insert the page content into the ".html" file cat_file "${PAGEID1}.content.shtml" >> "${PAGEID1/#*\///tmp/}.html" fi #### Insert the page divider or horizontal rule and page #### footer into the ".html". file cat_file "hr.shtml" >> "${PAGEID1/#*\///tmp/}.html" cat_file "footer.shtml" >> "${PAGEID1/#*\///tmp/}.html" #### End the ".html" file with the appropriate HTML tags print "" >> "${PAGEID1/#*\///tmp/}.html" fi done < ${DATAFILE} #### Cleanup any remaining temporary files rm -f "${DATATMP0}" rm -f "${DATATMP1}" rm -f "${DATATMP2}" } ################################################################ menugen "${@}"