home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-12-10 | 15.4 KB | 552 lines | [TEXT/ALFA] |
- #=== nowrap =====================================================================
- #
- # CodeWarrior Interaction
- #
- # Metrowerks currently has an incomplete appleevent interface.
- # Apple events can be used to direct CodeWarrior to compile
- # or add individual files, make the project, etc. However,
- # there is currently no provision to report specific errors
- # back to the controller.
- #
- #================================================================================
-
- alpha::menu codewarriorMenu 1.1 "•268" "" {
- set cwdebugMenu "•274"
- } uninstall {this-file} maintainer {
- "Vince Darley" darley@fas.harvard.edu <http://www.fas.harvard.edu/~darley/>
- } help {file "CodeWarrior"}
-
- alpha::package require modeSearchPaths 1.0
-
- hook::register savePostHook cw::modified "C++" "C"
- newPref flag debugger 0 cw
- newPref flag switchWhenCompiling 1 cw
- newPref var cwSearchPath "" cw
-
- ensureset CWCompilerSig CWIE
- ensureset CWDebuggerSig MWDB
-
- proc codewarriorMenu {} {}
-
- menu -n "$codewarriorMenu" -p cw::menuProc {
- "help"
- "/-<UswitchTo"
- {menu -m -n werksFlags {}}
- "createFileset"
- {menu -m -n headers {}}
- "(-"
- "addFile"
- "/K<Ucompile"
- "compileFiles"
- "checkSyntax"
- "precompile…"
- "(-"
- "openHeader"
- "(-"
- "/U<Uupdate"
- "/M<Umake"
- "(-"
- "/D<UgotoDebugger"
- "/B<UsetBreakpoint"
- "clearBreakpoint"
- "/J<UshowSource"
- "(-"
- "/N<UnextError"
- "/R<Urun"
- }
-
- menu::buildFlagMenu werksFlags array cwmodeVars
- mode::rebuildSearchPathMenu
-
- proc cw::help {} {
- global HOME
- edit -r "$HOME:Help:CodeWarrior"
- }
-
- set CWCLASS MMPR
- set CDCLASS MWDB
-
- proc cw::nextError {} {
- nextMatch "*Compiler Errors*"
- }
-
- proc cw::menuProc {menu item} {
- cw::$item
- }
-
- proc cw::switchTo {} {
- global CODEWarrior
- cw::check
- switchTo $CODEWarrior
- }
-
- proc cw::make {} {cw::killErrors; cw::Do Make}
- proc cw::update {} {cw::Do UpdP}
-
- proc cw::Do {param} {
- global CODEWarrior CWCLASS ALPHA
- cw::check
- switchTo $CODEWarrior
- if {[string length [set res [AEBuild -r -t 500000 $CODEWarrior $CWCLASS $param "Errs" "bool(«01»)"]]]} {
- cw::errors $res
- }
- }
-
- proc cw::run {} {
- global CODEWarrior CWCLASS ALPHA cwmodeVars
- cw::check
- cw::killErrors
- set bug $cwmodeVars(cwdebugger)
- switchTo $CODEWarrior
- if {[string length [set res [AEBuild -r -t 500000 $CODEWarrior $CWCLASS RunP "Errs" "bool(«01»)" DeBg $bug]]]} {
- cw::errors $res
- }
- }
-
- proc cw::precompile {} {
- global CODEWarrior CWCLASS res
- cw::check
- set fname [win::Current]
- set targ [putfile "Precompile target:"]
- switchTo $CODEWarrior
- if {[string length [set res [AEBuild $CODEWarrior $CWCLASS PreC "----" [makeAlis $fname] "Errs" "bool(«01»)" Targ [makeAlis $targ]]]] > 40} {
- cw::errors $res
- } else {
- if {[regexp {errn:([-0-9]+)} $res dummy errno]} {
- message "Error number: $errno"
- }
- }
- }
-
- proc cw::addFile {} {
- global CODEWarrior CWCLASS
- cw::check
- switchTo $CODEWarrior
- set fname [win::Current]
- set res [AEBuild -t 500000 -q $CODEWarrior $CWCLASS AddF "----" [makeAlis $fname]]
- }
-
- proc cw::checkSyntax {} {
- global CODEWarrior CWCLASS res
- cw::check
- # switchTo $CODEWarrior
- set fname [win::Current]
- if {[string length [set res [AEBuild -t 500000 -r $CODEWarrior $CWCLASS Chek "----" [concat {[alis(«} [coerce TEXT $fname -x alis] {»)]}] "Errs" "bool(«01»)"]]] > 40} {
- cw::errors $res
- }
- }
-
-
- proc cw::killErrors {} {
- set wins [winNames]
- if {[set res [lsearch $wins "*Compiler Errors*"]] >= 0} {
- set name [lindex $wins $res]
- bringToFront $name
- killWindow
- }
- }
-
-
- proc cw::compile {} {
- global CODEWarrior CWCLASS res ALPHA cwmodeVars
- save
- cw::check
- set fname [win::Current]
- cw::killErrors
- if {$cwmodeVars(cwswitchWhenCompiling)} {
- switchTo $CODEWarrior
- }
- if {[string length [set res [AEBuild -t 500000 -r $CODEWarrior $CWCLASS Comp "----" [makeAlis $fname] "Errs" "bool(«01»)"]]] > 40} {
- cw::errors $res
- }
- switchTo $ALPHA
- }
-
-
- proc cw::compileFiles {} {
- global CODEWarrior CWCLASS res ALPHA win::Modes
- saveAll
- cw::check
- set files {}
- set wins [winNames -f]
- set md [set win::Modes([lindex $wins 0])]
- foreach w $wins {
- if {$md == [set win::Modes($w)]} {
- lappend files $w
- }
- }
- cw::killErrors
- switchTo $CODEWarrior
- if {[string length [set res [AEBuild -t 500000 -r $CODEWarrior $CWCLASS Comp "----" [makeAlises $files] "Errs" "bool(«01»)"]]] > 40} {
- cw::errors $res
- }
- switchTo $ALPHA
- }
-
-
- proc cw::GetFiles {} {
- global CODEWarrior CWCLASS
- cw::check
- set res [AEBuild -t 500000 -r $CODEWarrior $CWCLASS GSeg]
- regexp {\[(.*)\]} $res dummy segs
- regsub -all {, Seg} $segs {•} segs
- set ind 1
- foreach seg [split $segs {•}] {
- regexp {NumF:([0-9]+)} $seg dummy num
-
- while {$num > 0} {
- set res [AEBuild -t 500000 -r $CODEWarrior $CWCLASS GFil "----" "long($num)" Segm "long($ind)"]
- if {[regexp {FTxt} $res]} {
- regexp {«(.*)»} $res dummy spec
- set f [specToPathName $spec]
- message $f
- lappend files $f
- }
- incr num -1
- }
- incr ind
- }
- return $files
- }
-
- proc cw::createFileset {} {
- createWarriorFileset
- rebuildAllFilesets
- }
-
-
- proc createWarriorFileset {} {
- global gfileSets gfileSetsType
-
- set name [prompt "Fileset name? " "CodeWarrior"]
- set gfileSets($name) [lsort -command sortByTail [cw::GetFiles]]
- set gfileSetsType($name) codewarrior
-
- if {[askyesno "Save project fileset?"] == "yes"} {
- addArrDef gfileSets $name $gfileSets($name)
- addArrDef gfileSetsType $name codewarrior
- }
- return $name
- }
-
-
- # the error reply from CodeWarrior looks like this
- # [ErrM{ErrT:ErCW, ErrS:“function declaration hides inherited virtual function”, file:fss («FFFB000014371443536D617274537464506F7075704D656E752E6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000»), ErrL:64}, ...]
- #
- # ErrT is the error type parameter
- # ErCW indicates a warning
- # ErCE indicates an error
- # Improvements by jdunning@cs.Princeton.EDU (John Dunning)
- proc cw::errors {res} {
- global win::Modes tileLeft tileTop tileWidth errorHeight
-
- if {[regexp {\[.*\]} $res res]} {
- # trim off the outside brackets
- set res [string trim $res {[]}]
-
- # replace all the returns in the error list with spaces. this is
- # necessary because CW 7.0 can return multi-line error messages,
- # which aren't processed correctly by this function.
- regsub -all "\r" $res " " res
-
- # delete the first ErrM, and replace the remaining ones (and the preceeding commas)
- # with returns
- regsub {ErrM} $res "" res
- regsub -all {, ErrM} $res "\r" res
-
- set text ""
- set errors 0
- set warnings 0
- set messages 0
- set link 0
-
- # split the string into separate lines, one error per line. only process
- # process the first 101 errors
- foreach err [lrange [split $res "\r"] 0 100] {
- # the last two letters in ErrT:Er.. signal whether it's a compile (C) or link (L)
- # error and whether it's an error (E) or a warning (W). stick the rest of
- # the error message back into err.
- if {[regexp {ErrT:Er(.)(.),[ \t]*(.*)} $err unused compileOrLink errorOrWarning err]} {
- if {$errorOrWarning == "E"} {
- # mark actual errors with a bullet
- append text " • "
- incr errors
- } else {
- # mark warnings with a delta
- append text " Δ "
- incr warnings
- }
-
- if {$compileOrLink == "C"} {
- # we have a compile error, so strip out the error message, the filespec
- # and the line number
- if {[regexp {ErrS:“(.*)”.*«(.*)».*ErrL:([0-9]+)} $err unused errorString fileSpec lineNumber]} {
- # conver the filespec that was returned in the apple event into a pathname
- # so we can display it
- set pathName [specToPathName $fileSpec]
-
- # append the file name (the tail of the pathname), the line number,
- # the error string, lots of tabs, and then the full pathname
- append text "\"[file tail $pathName]\"\t; Line $lineNumber: $errorString\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$pathName\r"
- }
- } else {
- # we got a link error
- set link 1
-
- # just strip out the error message. the file the error occurs in doesn't
- # seem to get included in the event
- if {[regexp {ErrS:“(.*)”} $err unused errorString]} {
- # append the error message
- append text "$errorString\r"
- }
- }
- } elseif {[regexp {“([^:]*): (.*)”} $err unused fileName message]} {
- # we got some sort of message, so strip out the associated file name and
- # the message. I'm not sure if CodeWarrior still returns anything of this form.
- append text "\"$fileName\" ; $message\r"
- incr messages
- }
- }
-
- set wins [winNames]
- if {$errors == 0 && $warnings == 0 && $messages == 0} {
- global killCompilerErrors
- set killCompilerErrors 1
- return
- }
-
- new -n {* Compiler Errors *} -g $tileLeft $tileTop $tileWidth $errorHeight -m Brws
- if {$link} {
- insertText "(Link: $errors errors, $warnings warnings, $messages messages)\r-----\r$text"
- } else {
- insertText "($errors errors, $warnings warnings, $messages messages: <cr> to go to line)\r-----\r$text"
- }
-
- display 0
- goto 0
- downBrowse
- setWinInfo dirty 0
- setWinInfo read-only 1
- gotoMatch
- }
- }
-
-
-
- proc cw::modified {fname} {
- global CWCompilerSig CWCLASS mode
- cw::checkRunning
- AEBuild -t 500000 $CODEWarrior $CWCLASS "Toch" "----" [makeAlis $fname]
- }
-
- proc cw::Touch {} {
- global CODEWarrior CWCLASS
- cw::check
- switchTo $CODEWarrior
- set fname [win::Current]
- set res [AEBuild -t 500000 -q $CODEWarrior $CWCLASS "Toch" "----" [makeAlis $fname]]
- }
-
- proc cw::check {} {
- global CODEWarrior modifiedVars CWCompilerSig
- app::launchElseTryThese {CWIE MMCC MPCC} CWCompilerSig
- set CODEWarrior [file tail [app::launchBack $CWCompilerSig]]
- }
-
- proc cw::checkDebug {} {
- global CODEDEBUGGER CWDebuggerSig modifiedVars
- app::launchElseTryThese {MPDB MWDB} CWDebuggerSig
- set CODEDEBUGGER [file tail [app::launchBack $CWDebuggerSig]]
- }
-
- proc cw::gotoDebugger {} {
- global CODEDEBUGGER
- cw::checkDebug
- switchTo $CODEDEBUGGER
- }
-
- proc cw::setBreakpoint {} {
- global CODEDEBUGGER CDCLASS res
- cw::checkDebug
- switchTo $CODEDEBUGGER
- set fname [win::Current]
- set ln [lindex [posToRowCol [getPos]] 0]
- set res [AEBuild -t 500000 -r $CODEDEBUGGER $CDCLASS "Sbrk" "----" [makeAlis $fname] "Line" "long($ln)"]
- }
-
- proc cw::clearBreakpoint {} {
- global CODEDEBUGGER CDCLASS res
- cw::checkDebug
- switchTo $CODEDEBUGGER
- set fname [win::Current]
- set ln [lindex [posToRowCol [getPos]] 0]
- set res [AEBuild -t 500000 -r $CODEDEBUGGER $CDCLASS "Cbrk" "----" [makeAlis $fname] "Line" "long($ln)"]
- }
-
-
- proc cw::showSource {} {
- global CODEDEBUGGER CDCLASS res
- cw::checkDebug
- switchTo $CODEDEBUGGER
- set fname [win::Current]
- set ln [lindex [posToRowCol [getPos]] 0]
- set res [AEBuild -t 500000 -r $CODEDEBUGGER $CDCLASS "Show" "----" [makeAlis $fname] "Line" "long($ln)"]
- }
- # "Soff" "long([getPos]" "Eoff" "long([selEnd])"
-
- proc cw::openHeader {} {
- if {[regexp {#include.*("|<)(.*)("|>)} [getText [lineStart [getPos]] [nextLineStart [getPos]]] d1 d1 inc]} {
- return [editIncludeFile $inc]
- }
- message "No include file found on this line!"
- beep
- }
-
-
- ##
- # from old "codeWarriorMenu+.tcl"
- #
- # July 15, 1996 Jonathan E. Guyer <mailto:j-guyer@nwu.edu>
- #
- # These routines implement an includes list for CodeWarrior when you
- # option-click in the title bar. It requires CodeWarrior IDE 1.6 or
- # greater (earlier versions didn't return file dependencies with
- # «MMPRGFil» events.
- #
- # As discussed within the code, it's not the
- # most efficient thing in the world, due to the IDE's
- # dain-bramaged object model. I hope to improve this in the future.
- ##
-
- proc cw::checkRunning {} {
- global CODEWarrior CWCompilerSig launchIDEifRequired
- if ![app::isRunning $CWCompilerSig CODEWarrior] {
- if ![app::isRunning {CWIE MMCC MPCC} CODEWarrior CWCompilerSig] {
- error "Not running"
- }
- }
- }
-
- proc cw::include {name} {
- global CODEWarrior cwpaths
-
- # This may be more trouble than it's worth:
- # I got tired of "* CodeWarrior Not Running *" messages when it _was_ running
- # (CODEWarrior wasn't defined yet) but this way it'll launch CW on an option-click,
- # whether you want it to or not.
- cw::checkRunning
-
- # Make sure the file is in the current project before we start iterating
- # through all its files.
-
- set blah [AEBuild -r $CODEWarrior "MMPR" "FInP" "----" "TEXT(“[file tail $name]”)"]
- # aevt\ansr{'----':[?]}
- if {![regexp {'----':\[([^]]*)\]} $blah dummy errCode]} {
- # aevt\ansr{errn:????}
- regexp {errn:([-0-9]*)} $blah dummy errCode
- }
-
- # error codes defined in CWAppleEvents.h in CodeWarrior's MacOS Examples
- if {$errCode == 1} {
- # errShell_ActionFailed
- set theReply {{(Action Failed}}
- } elseif {$errCode == 2} {
- # errShell_FileNotFound
- set theReply {{(Not in current CW project}}
- } elseif {$errCode == 6} {
- # errShell_NoOpenProject
- set theReply {{(No project open in CW}}
- } elseif {$errCode != 0} {
- lappend theReply "(CW AppleEvent Error: $errCode"
- }
-
- if {![info exists theReply]} {
-
- if {[info exists cwpaths]} {unset cwpaths}
-
- # CodeWarrior is a pain in the ass about this and won't just
- # return the file with a given name so we:
-
- # get list of Segments
-
- set blah [AEBuild -r $CODEWarrior "MMPR" "GSeg"]
- # aevt\ansr{'----':[Seg {...}, Seg {...}, ...]}
- if {![regexp {aevt\\ansr\{'----':\[.+\]\}} $blah]} {return {{(Empty project}}}
-
- # strip out everthing down to a list of file counts
-
- set fileCountList ""
- # ... Seg {... NumF:??, ...}, ...
- while {[regexp -indices {NumF:([0-9]*),?} $blah dummy mtchRange]} {
- set fileCountList [concat $fileCountList " " [string range $blah [lindex $mtchRange 0] [lindex $mtchRange 1]]]
- set blah [string range $blah [expr [lindex $mtchRange 1] + 1] [string length $blah]]
- }
-
- # then iterate through each file in each segment
- # until we find what we're looking for
-
- set segmentNumber 0
- set foundFile 0
- foreach fileCount $fileCountList {
- incr segmentNumber
- for {set fileNumber 1} {$fileNumber <= $fileCount} {incr fileNumber} {
- set blah [AEBuild -r $CODEWarrior "MMPR" "GFil" "----" $fileNumber "Segm" $segmentNumber]
- # aevt\ansr{'----':SrcF{... pnam:“?????.??” ...}}
- regexp {pnam:“([^”]*)”} $blah dummy fileName
- if {$fileName == $name} {
- set foundFile 1
- break
- }
- }
- if {$foundFile} {
- break
- }
-
- }
-
- # and finally break down the list of included files,
-
- if {$foundFile} {
- # aevt\ansr{'----':SrcF{... IncF:[fss («...»), ... ] ...}}
- regexp {IncF:\[([^]]*)\]} $blah dummy raw
- if {$raw == ""} {return {{(No includes}}}
- # fss («??????»), fss («??????»), ... , fss («??????») ...
- regsub -all {»[^«]*«} $raw { } raw
- # fss («?????? ?????? ... ??????») ...
- regsub {[^«]*«} $raw {} raw
- # ?????? ?????? ... ??????») ...
- regsub {».*} $raw {} raw
- # ?????? ?????? ... ??????
- foreach f $raw {
- # ?????? (really about a bazillion numbers)
- set path [specToPathName $f]
- set tl [file tail $path]
- set cwpaths($tl) $path
- lappend names $tl
- }
- set theReply [lsort -ignore $names]
- } else {
- # should never get here
- set theReply {{(Not in current CW project}}
- }
- }
- return $theReply
- }
-
- # Called by Alpha to get list of include files for popup.
- proc cw::getIncludeFiles {} {
- if {[catch {cw::include [win::CurrentTail]} ret]} {
- error {{(* CodeWarrior not running *}}
- }
- return $ret
- }
-
- proc cw::editIncludeFile {fname} {
- global cwpaths
- if [info exists cwpaths($fname)] {
- openFileQuietly $cwpaths($fname)
- } else {
- error "Not found!"
- }
- }
-