Annotation of micropolis/src/tclx/tcllib/buildhelp.tcl, revision 1.1

1.1     ! root        1: #
        !             2: # buildhelp.tcl --
        !             3: #
        !             4: # Program to extract help files from TCL manual pages or TCL script files.
        !             5: # The help directories are built as a hierarchical tree of subjects and help
        !             6: # files.  
        !             7: # 
        !             8: #------------------------------------------------------------------------------
        !             9: # Copyright 1992 Karl Lehenbauer and Mark Diekhans.
        !            10: #
        !            11: # Permission to use, copy, modify, and distribute this software and its
        !            12: # documentation for any purpose and without fee is hereby granted, provided
        !            13: # that the above copyright notice appear in all copies.  Karl Lehenbauer and
        !            14: # Mark Diekhans make no representations about the suitability of this
        !            15: # software for any purpose.  It is provided "as is" without express or
        !            16: # implied warranty.
        !            17: #------------------------------------------------------------------------------
        !            18: # $Id: buildhelp.tcl,v 2.1 1992/10/25 17:07:40 markd Exp $
        !            19: #------------------------------------------------------------------------------
        !            20: #
        !            21: # For nroff man pages, the areas of text to extract are delimited with:
        !            22: #
        !            23: #     '@help: subjectdir/helpfile
        !            24: #     '@endhelp
        !            25: #
        !            26: # start in column one. The text between these markers is extracted and stored
        !            27: # in help/subjectdir/help.  The file must not exists, this is done to enforced 
        !            28: # cleaning out the directories before help file generation is started, thus
        !            29: # removing any stale files.  The extracted text is run through:
        !            30: #
        !            31: #     nroff -man|col -xb   {col -b on BSD derived systems}
        !            32: #
        !            33: # If there is other text to include in the helpfile, but not in the manual 
        !            34: # page, the text, along with nroff formatting commands, may be included using:
        !            35: #
        !            36: #     '@:Other text to include in the help page.
        !            37: #
        !            38: # A entry in the brief file, used by apropos my be included by:
        !            39: #
        !            40: #     '@brief: Short, one line description
        !            41: #
        !            42: # These brief request must occur with in the bounds of a help section.
        !            43: #
        !            44: # If some header text, such as nroff macros, need to be preappended to the
        !            45: # text streem before it is run through nroff, then that text can be bracketed
        !            46: # with:
        !            47: #
        !            48: #     '@header
        !            49: #     '@endheader
        !            50: #
        !            51: # If multiple header blocks are encountered, they will all be preappended.
        !            52: #
        !            53: # For TCL script files, which are indentified because they end in ".tcl",
        !            54: # the text to be extracted is delimited by:
        !            55: #
        !            56: #    #@help: subjectdir/helpfile
        !            57: #    #@endhelp
        !            58: #
        !            59: # And brief lines are in the form:
        !            60: #
        !            61: #     #@brief: Short, one line description
        !            62: #
        !            63: # The only processing done on text extracted from .tcl files it to replace
        !            64: # the # in column one with a space.
        !            65: #
        !            66: #
        !            67: #-----------------------------------------------------------------------------
        !            68: # 
        !            69: # To run this program:
        !            70: #
        !            71: #   tcl buildhelp.tcl [-m mergeTree] -b brief.brf helpDir file-1 file-2 ...
        !            72: #
        !            73: # o -m mergeTree is a tree of help code, plus a brief file to merge with the
        !            74: #   help files that are to be extracted.  This will become part of the new
        !            75: #   help tree.  Used to merge in the documentation from UCB Tcl.
        !            76: # o -b specified the name of the brief file to create form the @brief entries.
        !            77: #   It must have an extension of ".brf".
        !            78: # o helpDir is the help tree root directory.  helpDir should  exists, but any
        !            79: #   subdirectories that don't exists will be created.  helpDir should be
        !            80: #   cleaned up before the start of manual page generation, as this program
        !            81: #   will not overwrite existing files.
        !            82: # o file-n are the nroff manual pages (.man) or .tcl or .tlib files to extract
        !            83: #   the help files from.
        !            84: #
        !            85: #-----------------------------------------------------------------------------
        !            86: 
        !            87: #-----------------------------------------------------------------------------
        !            88: # Truncate a file name of a help file if the system does not support long
        !            89: # file names.  If the name starts with `Tcl_', then this prefix is removed.
        !            90: # If the name is then over 14 characters, it is truncated to 14 charactes
        !            91: #  
        !            92: proc TruncFileName {pathName} {
        !            93:     global G_truncFileNames
        !            94: 
        !            95:     if {!$G_truncFileNames} {
        !            96:         return $pathName}
        !            97:     set fileName [file tail $pathName]
        !            98:     if {"[crange $fileName 0 3]" == "Tcl_"} {
        !            99:         set fileName [crange $fileName 4 end]}
        !           100:     set fileName [crange $fileName 0 13]
        !           101:     return "[file dirname $pathName]/$fileName"
        !           102: }
        !           103: 
        !           104: #-----------------------------------------------------------------------------
        !           105: # Proc to ensure that all directories for the specified file path exists,
        !           106: # and if they don't create them.  Don't use -path so we can set the
        !           107: # permissions.
        !           108: 
        !           109: proc EnsureDirs {filePath} {
        !           110:     set dirPath [file dirname $filePath]
        !           111:     if [file exists $dirPath] return
        !           112:     foreach dir [split $dirPath /] {
        !           113:         lappend dirList $dir
        !           114:         set partPath [join $dirList /]
        !           115:         if [file exists $partPath] continue
        !           116: 
        !           117:         mkdir $partPath
        !           118:         chmod u=rwx,go=rx $partPath
        !           119:     }
        !           120: }
        !           121: 
        !           122: 
        !           123: #-----------------------------------------------------------------------------
        !           124: #
        !           125: # Proc to extract nroff text to use as a header to all pass to nroff when
        !           126: # processing a help file.
        !           127: #    manPageFH - The file handle of the manual page.
        !           128: #
        !           129: 
        !           130: proc ExtractNroffHeader {manPageFH} {
        !           131:     global nroffHeader
        !           132:     while {[gets $manPageFH manLine] >= 0} {
        !           133:         if {[string first "'@endheader" $manLine] == 0} {
        !           134:             break;
        !           135:             }
        !           136:         if {[string first "'@:" $manLine] == 0} {
        !           137:             set manLine [csubstr manLine 3 end]
        !           138:             }
        !           139:         append nroffHeader "$manLine\n"
        !           140:         }
        !           141: }
        !           142: 
        !           143: #-----------------------------------------------------------------------------
        !           144: #
        !           145: # Proc to extract a nroff help file when it is located in the text.
        !           146: #    manPageFH - The file handle of the manual page.
        !           147: #    manLine - The '@help: line starting the data to extract.
        !           148: #
        !           149: 
        !           150: proc ExtractNroffHelp {manPageFH manLine} {
        !           151:     global G_helpDir nroffHeader G_briefHelpFH G_colArgs
        !           152: 
        !           153:     set helpName [string trim [csubstr $manLine 7 end]]
        !           154:     set helpFile [TruncFileName "$G_helpDir/$helpName"]
        !           155:     if {[file exists $helpFile]} {
        !           156:         error "Help file already exists: $helpFile"}
        !           157:     EnsureDirs $helpFile
        !           158:     set helpFH [open "| nroff -man | col $G_colArgs > $helpFile" w]
        !           159:     echo "    creating help file $helpName"
        !           160: 
        !           161:     # Nroff commands from .TH macro to get the formatting right.  The `\n'
        !           162:     # are newline separators to output, the `\\n' become `\n' in the text.
        !           163:         
        !           164:     puts $helpFH ".ad b\n.PD\n.nrIN \\n()Mu\n.nr)R 0\n.nr)I \\n()Mu"
        !           165:     puts $helpFH ".nr)R 0\n.\}E\n.DT\n.na\n.nh"
        !           166:     puts $helpFH $nroffHeader
        !           167:     set foundBrief 0
        !           168:     while {[gets $manPageFH manLine] >= 0} {
        !           169:         if {[string first "'@endhelp" $manLine] == 0} {
        !           170:             break;
        !           171:         }
        !           172:         if {[string first "'@brief:" $manLine] == 0} {
        !           173:             if $foundBrief {
        !           174:                 error {Duplicate "'@brief" entry"}
        !           175:             }
        !           176:             set foundBrief 1
        !           177:            puts $G_briefHelpFH "$helpName\t[csubstr $manLine 8 end]"
        !           178:             continue;
        !           179:         }
        !           180:         if {[string first "'@:" $manLine] == 0} {
        !           181:             set manLine [csubstr $manLine 3 end]
        !           182:         }
        !           183:         if {[string first "'@help" $manLine] == 0} {
        !           184:             error {"'@help" found within another help section"}
        !           185:         }
        !           186:         puts $helpFH $manLine
        !           187:         }
        !           188:     close $helpFH
        !           189:     chmod a-w,a+r $helpFile
        !           190: }
        !           191: 
        !           192: #-----------------------------------------------------------------------------
        !           193: #
        !           194: # Proc to extract a tcl script help file when it is located in the text.
        !           195: #    ScriptPageFH - The file handle of the .tcl file.
        !           196: #    ScriptLine - The #@help: line starting the data to extract.
        !           197: #
        !           198: 
        !           199: proc ExtractScriptHelp {ScriptPageFH ScriptLine} {
        !           200:     global G_helpDir G_briefHelpFH
        !           201:     set helpName [string trim [csubstr $ScriptLine 7 end]]
        !           202:     set helpFile "$G_helpDir/$helpName"
        !           203:     if {[file exists $helpFile]} {
        !           204:         error "Help file already exists: $helpFile"}
        !           205:     EnsureDirs $helpFile
        !           206:     set helpFH [open $helpFile w]
        !           207:     echo "    creating help file $helpName"
        !           208:     set foundBrief 0
        !           209:     while {[gets $ScriptPageFH ScriptLine] >= 0} {
        !           210:         if {[string first "#@endhelp" $ScriptLine] == 0} {
        !           211:             break;
        !           212:         }
        !           213:         if {[string first "#@brief:" $ScriptLine] == 0} {
        !           214:             if $foundBrief {
        !           215:                 error {Duplicate "#@brief" entry"}
        !           216:             }
        !           217:             set foundBrief 1
        !           218:            puts $G_briefHelpFH "$helpName\t[csubstr $ScriptLine 8 end]"
        !           219:             continue;
        !           220:         }
        !           221:         if {[string first "#@help" $ScriptLine] == 0} {
        !           222:             error {"#@help" found within another help section"}
        !           223:         }
        !           224:         if {[clength $ScriptLine] > 1} {
        !           225:             set ScriptLine " [csubstr $ScriptLine 1 end]"
        !           226:         } else {
        !           227:             set ScriptLine ""
        !           228:         }
        !           229:         puts $helpFH $ScriptLine
        !           230:         }
        !           231:     close $helpFH
        !           232:     chmod a-w,a+r $helpFile
        !           233: }
        !           234: 
        !           235: #-----------------------------------------------------------------------------
        !           236: #
        !           237: # Proc to scan a nroff manual file looking for the start of a help text
        !           238: # sections and extracting those sections.
        !           239: #    pathName - Full path name of file to extract documentation from.
        !           240: #
        !           241: 
        !           242: proc ProcessNroffFile {pathName} {
        !           243:    global G_nroffScanCT G_scriptScanCT nroffHeader
        !           244: 
        !           245:    set fileName [file tail $pathName]
        !           246: 
        !           247:    set nroffHeader {}
        !           248:    set manPageFH [open $pathName r]
        !           249:    echo "    scanning $pathName"
        !           250:    set matchInfo(fileName) [file tail $pathName]
        !           251:    scanfile $G_nroffScanCT $manPageFH
        !           252:    close $manPageFH
        !           253: }
        !           254: 
        !           255: #-----------------------------------------------------------------------------
        !           256: #
        !           257: # Proc to scan a Tcl script file looking for the start of a
        !           258: # help text sections and extracting those sections.
        !           259: #    pathName - Full path name of file to extract documentation from.
        !           260: #
        !           261: 
        !           262: proc ProcessTclScript {pathName} {
        !           263:    global G_scriptScanCT nroffHeader
        !           264: 
        !           265:    set scriptFH [open "$pathName" r]
        !           266: 
        !           267:    echo "    scanning $pathName"
        !           268:    set matchInfo(fileName) [file tail $pathName]
        !           269:    scanfile $G_scriptScanCT $scriptFH
        !           270:    close $scriptFH
        !           271: }
        !           272: 
        !           273: #-----------------------------------------------------------------------------
        !           274: # Proc to copy the help merge tree, excluding the brief file and RCS files
        !           275: # 
        !           276: 
        !           277: proc CopyMergeTree {helpDirPath mergeTree} {
        !           278:     if {"[cindex $helpDirPath 0]" != "/"} {
        !           279:         set helpDirPath "[pwd]/$helpDirPath"
        !           280:     }
        !           281:     set oldDir [pwd]
        !           282:     cd $mergeTree
        !           283: 
        !           284:     set curHelpDir "."
        !           285: 
        !           286:     for_recursive_glob mergeFile {.} {
        !           287:         if [string match "*/RCS/*" $mergeFile] continue
        !           288: 
        !           289:         set helpFile "$helpDirPath/$mergeFile"
        !           290:         if [file isdirectory $mergeFile] continue
        !           291: 
        !           292:         if {[file exists $helpFile]} {
        !           293:             error "Help file already exists: $helpFile"}
        !           294:         EnsureDirs $helpFile
        !           295:         set inFH [open $mergeFile r]
        !           296:         set outFH [open $helpFile w]
        !           297:         copyfile $inFH $outFH
        !           298:         close $outFH
        !           299:         close $inFH
        !           300:         chmod a-w,a+r $helpFile
        !           301:     }
        !           302:     cd $oldDir
        !           303: }
        !           304: 
        !           305: #-----------------------------------------------------------------------------
        !           306: # GenerateHelp: main procedure.  Generates help from specified files.
        !           307: #    helpDirPath - Directory were the help files go.
        !           308: #    mergeTree - Help file tree to merge with the extracted help files.
        !           309: #    briefFile - The name of the brief file to create.
        !           310: #    sourceFiles - List of files to extract help files from.
        !           311: 
        !           312: proc GenerateHelp {helpDirPath briefFile mergeTree sourceFiles} {
        !           313:     global G_helpDir G_truncFileNames G_nroffScanCT
        !           314:     global G_scriptScanCT G_briefHelpFH G_colArgs
        !           315: 
        !           316:     echo ""
        !           317:     echo "Begin building help tree"
        !           318: 
        !           319:     # Determine version of col command to use (no -x on BSD)
        !           320:     if {[system {col -bx </dev/null >/dev/null 2>&1}] != 0} {
        !           321:         set G_colArgs {-b}
        !           322:     } else {
        !           323:         set G_colArgs {-bx}
        !           324:     }
        !           325:     set G_helpDir [glob $helpDirPath]
        !           326: 
        !           327:     if {![file isdirectory $G_helpDir]} {
        !           328:         error [concat "$G_helpDir is not a directory or does not exist. "  
        !           329:                       "This should be the help root directory"]
        !           330:     }
        !           331:         
        !           332:     set status [catch {set tmpFH [open $G_helpDir/AVeryVeryBigFileName w]}]
        !           333:     if {$status != 0} {
        !           334:         set G_truncFileNames 1
        !           335:     } else {
        !           336:         close $tmpFH
        !           337:         unlink $G_helpDir/AVeryVeryBigFileName
        !           338:         set G_truncFileNames 0
        !           339:     }
        !           340: 
        !           341:     set G_nroffScanCT [scancontext create]
        !           342: 
        !           343:     scanmatch $G_nroffScanCT "^'@help:" {
        !           344:         ExtractNroffHelp $matchInfo(handle) $matchInfo(line)
        !           345:         continue
        !           346:     }
        !           347: 
        !           348:     scanmatch $G_nroffScanCT "^'@header" {
        !           349:         ExtractNroffHeader $matchInfo(handle)
        !           350:         continue
        !           351:     }
        !           352:     scanmatch $G_nroffScanCT "^'@endhelp" {
        !           353:         error [concat {"'@endhelp" without corresponding "'@help:"} \
        !           354:                  ", offset = $matchInfo(offset)"]
        !           355:     }
        !           356:     scanmatch $G_nroffScanCT "^'@brief" {
        !           357:         error [concat {"'@brief" without corresponding "'@help:"}
        !           358:                  ", offset = $matchInfo(offset)"]
        !           359:     }
        !           360: 
        !           361:     set G_scriptScanCT [scancontext create]
        !           362:     scanmatch $G_scriptScanCT "^#@help:" {
        !           363:         ExtractScriptHelp $matchInfo(handle) $matchInfo(line)
        !           364:     }
        !           365: 
        !           366:     if ![lempty $mergeTree] {
        !           367:         echo "    Merging tree: $mergeTree"
        !           368:         CopyMergeTree $helpDirPath $mergeTree
        !           369:     }
        !           370: 
        !           371: 
        !           372:     if {[file extension $briefFile] != ".brf"} {
        !           373:         puts stderr "Brief file \"$briefFile\" must have an extension \".brf\""
        !           374:         exit 1
        !           375:     }
        !           376:     if [file exists $G_helpDir/$briefFile] {
        !           377:         puts stderr "Brief file \"$G_helpDir/$briefFile\" already exists"
        !           378:         exit 1
        !           379:     }
        !           380:     set G_briefHelpFH [open "|sort > $G_helpDir/$briefFile" w]
        !           381: 
        !           382:     foreach manFile $sourceFiles {
        !           383:         set manFile [glob $manFile]
        !           384:         set ext [file extension $manFile]
        !           385:         if {"$ext" == ".man"} {
        !           386:             set status [catch {ProcessNroffFile $manFile} msg]
        !           387:         } else {
        !           388:             set status [catch {ProcessTclScript $manFile} msg]
        !           389:         }
        !           390:         if {$status != 0} {
        !           391:             echo "Error extracting help from: $manFile"
        !           392:             echo $msg
        !           393:             global errorInfo interactiveSession
        !           394:             if {!$interactiveSession} {
        !           395:                 echo $errorInfo
        !           396:                 exit 1
        !           397:             }
        !           398:         }
        !           399:     }
        !           400: 
        !           401:     close $G_briefHelpFH
        !           402:     chmod a-w,a+r $G_helpDir/$briefFile
        !           403:     echo "*** completed extraction of all help files"
        !           404: }
        !           405: 
        !           406: #-----------------------------------------------------------------------------
        !           407: # Print a usage message and exit the program
        !           408: proc Usage {} {
        !           409:     puts stderr {Wrong args: [-m mergetree] -b briefFile helpdir manfile1 [manfile2..]}
        !           410:     exit 1
        !           411: }
        !           412: 
        !           413: #-----------------------------------------------------------------------------
        !           414: # Main program body, decides if help is interactive or batch.
        !           415: 
        !           416: if {$interactiveSession} {
        !           417:     echo "To extract help, use the command:"
        !           418:     echo {GenerateHelp helpdir -m mergetree file-1 file-2 ...}
        !           419: } else {
        !           420:     set mergeTree {}
        !           421:     set briefFile {}
        !           422:     while {[string match "-*" [lindex $argv 0]]} {
        !           423:         set flag [lvarpop argv 0]
        !           424:         case $flag in {
        !           425:             "-m" {set mergeTree [lvarpop argv]}
        !           426:             "-b" {set briefFile [lvarpop argv]}
        !           427:             default Usage
        !           428:         }
        !           429:     }
        !           430:     if {[llength $argv] < 2} {
        !           431:         Usage
        !           432:     }
        !           433:     if [lempty $briefFile] {
        !           434:        puts stderr {must specify -b argument}
        !           435:        Usage 
        !           436:     }
        !           437:     GenerateHelp [lindex $argv 0] $briefFile $mergeTree [lrange $argv 1 end]
        !           438:    
        !           439: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.