home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / common / msdev98 / macros / sample.dsm < prev   
Text File  |  1998-05-05  |  25KB  |  767 lines

  1. '------------------------------------------------------------------------------
  2. 'FILE DESCRIPTION: SAMPLE.DSM is a collection of sample editor macros.
  3. '------------------------------------------------------------------------------
  4.  
  5. 'This routine has many uses if you are trying to determine the type of source 
  6. '    file.
  7. 'Return value:  0 Unknown file type
  8. '               1 C-related file, this includes .c, .cpp, .cxx, .h, .hpp, .hxx
  9. '               2 Java-related file, this includes .jav, .java
  10. '               3 ODL-style file, .odl, .idl
  11. '               4 Resource file, .rc, .rc2
  12. '               5 HTML-style file, this includes .html, and .htm
  13. '               6 VBS-style file, .dsm
  14. '               7 Def-style file, .def
  15. 'USE: Pass this function the document that you wish to get information for.
  16. Function FileType (ByVal doc)
  17.     ext = doc.Name
  18.     FileType = 0
  19.     pos = Instr(ext, ".")
  20.     if pos > 0 then
  21.         Do While pos <> 1
  22.             ext = Mid(ext, pos, Len(ext) - pos + 1)
  23.             pos = Instr(ext, ".")
  24.         Loop
  25.         ext = LCase(ext)
  26.     end if
  27.     If ext = ".rc" Or ext = ".rc2" Then
  28.         FileType = 4
  29.     ElseIf doc.Language = dsCPP Then
  30.         FileType = 1
  31.     ElseIf doc.Language = dsJava Then
  32.         FileType = 2
  33.     ElseIf doc.Language = dsIDL Then
  34.         FileType = 3
  35.     ElseIf doc.Language = dsHTML_IE3 Or doc.Language = dsHTML_RFC1866 Then
  36.         FileType = 5  
  37.     ElseIf doc.Language = dsVBSMacro Then ' 
  38.         FileType = 6  
  39.     ElseIf ext = ".def" Then
  40.         FileType = 7
  41.     Else 
  42.         FileType = 0
  43.     End If 
  44. End Function
  45.  
  46.  
  47. 'This routine has many uses if you are trying to determine if an identifier
  48. '  is a valid C identifier.
  49. '  These identifiers do not include qualification syntax, for example:
  50. '  foo.bar is not valid
  51. '  foo is valid
  52. 'Parameters:    String to test for a valid C identifier.
  53. 'Return value:  True: passed parameter is a valid C identifier.
  54. '               False: passed parameter is not a valid C identifier.
  55. Function ValidId(Id)
  56.     ValidId = True
  57.  
  58.     'Don't permit an empty string
  59.     ' (how can you identify nothing with something?)
  60.     if Id = "" then 
  61.       ValidID = False
  62.       Exit Function
  63.     End If
  64.  
  65.     For i = 1 To Len(Id)
  66.       if Mid(Id, i, 1) < "a" Or Mid(Id, i, 1) > "z" Then
  67.         if Mid(Id, i, 1) < "A" Or Mid(Id, i, 1) > "Z" Then
  68.             if Mid(Id, i, 1) < "0" Or Mid(Id, i, 1) > "9" Then
  69.                 if Mid(Id, i, 1) <> "_" Then
  70.                     ValidId = False
  71.                 End if
  72.             End If
  73.         End If    
  74.       End If
  75.     Next
  76.     If IsNumeric(Left(Id, 1)) = True Then
  77.         ValidId = False
  78.     End If
  79. End Function
  80.  
  81.  
  82. Dim ParamArr ()  ' Dynamic array to store function arguments.
  83.  
  84. Sub AddFunctionDescription ( )
  85. 'DESCRIPTION: Creates a comment block for the currently selected C/C++ function prototype
  86.  
  87.     'Throughout this file, ActiveDocument.Selection is used in place 
  88.     'of ActiveDocument.Selection.Text.  The two are equivalent, and can 
  89.     'be used interchangeably. The reason for the equivalence is that
  90.     'Text is regarded as the default property to use. All uses of
  91.     'ActiveDocument.Selection without any other property default to the Text
  92.     'property.
  93.     if ActiveDocument.Language = dsCPP Then
  94.         Header = StripTabs(Trim(ActiveDocument.Selection))
  95.  
  96.         'Get the function return type.
  97.         if Header <> "" then
  98.             Reti = InStr(Header, " ")
  99.             Loc = InStr(Header, "(")
  100.             if Reti < Loc Then
  101.               RetTp = Left(Header, Reti)
  102.               Header = Right(Header, Len(Header) - Reti)
  103.             End If
  104.  
  105.             'Get the function name.
  106.             Loc = InStr(Header, "(") - 1
  107.             Loc2 = InStr(Header, ")")
  108.             if Loc > 0 And Loc2 > 0 then 'make sure there is a '(' and a ')'
  109.                 fcName = Left(Header, Loc)
  110.                 Header = Right(Header, Len(Header) - Len(fcName))
  111.  
  112.                 'Do we have storage type on the return type?
  113.                 Trim (fcName)
  114.                 If InStr(fcName," ") <> 0 Then
  115.                     retTp = retTp + Left(fcName,InStr (fcName," "))
  116.                     fcName = Right(fcName, Len(fcName) - InStr(fcName," "))
  117.                 End If
  118.  
  119.                 'Get the function parameters.
  120.                 iPrm = 0
  121.                 iPrmA = 0
  122.                 prms = Header 
  123.  
  124.                 'Count the number of parameters. 
  125.                 Do While InStr(prms, ",") <> 0
  126.                     iPrm = iPrm + 1
  127.                     prms = Right(prms, Len(prms) - InStr(prms, ",")) 
  128.                 Loop 
  129.                 
  130.                 'Store the parameter list in the array.
  131.                 If iPrm > 0 Then  ' If multiple params.
  132.                     iPrm = iPrm + 1
  133.                     iPrmA = iPrm
  134.                     Redim ParamArr(iPrm)
  135.                     Do While InStr(header, ",") <> 0
  136.                         ParamArr(iPrm) = Left(Header, InStr (Header, ",") - 1)
  137.                         'Remove brace from first parameter.
  138.                         If InStr(ParamArr(iPrm), " (") <> 0 Then
  139.                             ParamArr(iPrm) = Right(ParamArr(iPrm), _
  140.                                     Len(ParamArr(iPrm))-InStr(ParamArr(iPrm)," ("))
  141.                             Trim(ParamArr(iPrm))
  142.                         End If
  143.                         Header = Right(Header, Len(Header) - InStr(Header,","))
  144.                         iPrm = iPrm - 1 
  145.                         Loop 
  146.                     ParamArr(iPrm) = Header 
  147.                     'Remove trailing brace from last parameter.
  148.                     If InStr(ParamArr(iPrm), ")") <> 0 Then
  149.                         ParamArr(iPrm) = Left(ParamArr(iPrm), _
  150.                                 InStr(ParamArr(iPrm), ")") - 1)
  151.                         Trim(ParamArr(iPrm))
  152.                     End If
  153.                 Else 'Possibly one param.
  154.                     Redim ParamArr(1)
  155.                     Header = Right(Header, Len(Header) - 1) ' Strip the first brace.
  156.                     Trim(Header)
  157.                     ParamArr(1) = StripTabs(Header)
  158.                     If InStr(ParamArr(1), ")") <> 1 Then
  159.                         ParamArr(1) = Left(ParamArr(1), InStr(ParamArr(1), ")") - 1)
  160.                         Trim(ParamArr(1))
  161.                         iPrmA = 1
  162.                     End If
  163.                 End If
  164.  
  165.                 'Position the cursor one line above the selected text.
  166.                 ActiveDocument.Selection.LineUp
  167.                 ActiveDocument.Selection.LineDown
  168.                 ActiveDocument.Selection.StartOfLine
  169.                 ActiveDocument.Selection = vbLf
  170.  
  171.                 Descr = "// Function name    : " + fcName + _
  172.                         vbLf + "// Description        : " + _ 
  173.                         vbLf +  "// Return type        : " + RetTp + vbLf
  174.                 
  175.                 'Print the parameter list. 
  176.                 Last = iPrmA
  177.                 Do While iPrmA <> 0
  178.                     'Remove a line feed from any of the arguments.
  179.                     If InStr(ParamArr(iPrmA), vbLf) <> 0 Then
  180.                         ParamArr(iPrmA) = Right(ParamArr(iPrmA), _
  181.                                 (Len(ParamArr(iPrmA)) - _
  182.                                 InStr(ParamArr(iPrmA), vbLf)))
  183.                         Trim(ParamArr(iPrmA))
  184.                     End If
  185.                     ParamArr(iPrmA) = StripTabs(ParamArr(iPrmA))
  186.                     'If there are 2+ parameters, the first parameter will 
  187.                     'have a '(' prepended to it, remove it here:
  188.                     if iPrmA = Last AND Last <> 1 then
  189.                       ParamArr(iPrmA) = Right(ParamArr(iPrmA), _
  190.                             Len(ParamArr(iPrmA)) - 1)
  191.                     End If
  192.                     Descr = Descr + "// Argument         : " + _
  193.                             ParamArr(iPrmA) + vbLf
  194.                     iPrmA = iPrmA - 1
  195.                 Loop
  196.                 ActiveDocument.Selection = Descr
  197.             Else
  198.                 MsgBox("It is possible that the function you are trying to"+_
  199.                         " work with has a syntax error.")
  200.             End if
  201.         End If
  202.     Else
  203.         MsgBox("You need to have an active C/C++ document open"+ _
  204.                 vbLF+"with the function prototype selected.")
  205.     End If
  206. End Sub
  207.  
  208. 'Strips the leading tab spaces. 
  209. Function StripTabs (ByVal MyStr)
  210.     Do While InStr(MyStr, vbTab) <> 0
  211.         MyStr = Right(MyStr, Len(MyStr) - InStr(MyStr, vbTab)) 
  212.     Loop 
  213.     StripTabs = Trim(MyStr)
  214. End Function
  215.  
  216. Sub ToggleCommentStyle ( )
  217. 'DESCRIPTION: Toggles between comment styles /* and //.
  218.  
  219.     TmpBlock = ""
  220.     CmtBlock = ActiveDocument.Selection
  221.     TypeOfFile = FileType(ActiveDocument)
  222.     If TypeOfFile > 0 And TypeOfFile < 5 Then   'C/C++ style comment.
  223.         'Get the first two characters of the comment block.
  224.         Trim(CmtBlock)
  225.         If Instr(CmtBlock,"//") <> 0 Then 
  226.             Do While Instr (CmtBlock,"//") <> 0
  227.                 TmpBlock = TmpBlock + Left (CmtBlock, Instr (CmtBlock,"//") - 1)
  228.                 CmtBlock = Right(CmtBlock, (Len(CmtBlock) - (Instr(CmtBlock,_
  229.                         "//") + 1)))
  230.             Loop
  231.             CmtBlock = "/*" + TmpBlock + CmtBlock + "*/"
  232.         ElseIf Instr(CmtBlock, "/*") <> 0 Then 
  233.             CmtBlock = Right(CmtBlock, Len(CmtBlock) - (Instr(CmtBlock,"/*")_
  234.                     + 1))
  235.             Do While Instr (CmtBlock, vbLf) <> 0
  236.                 TmpBlock = TmpBlock + Left (CmtBlock, Instr(CmtBlock, vbLf))_
  237.                         + "//"
  238.                 CmtBlock = Right(CmtBlock, (Len(CmtBlock) - (Instr(CmtBlock,_
  239.                         vbLf))))
  240.             Loop
  241.             CmtBlock = "//" + TmpBlock + Trim(CmtBlock)
  242.             CmtBlock = Left(CmtBlock, Instr(CmtBlock,"*/")-1)
  243.         End If
  244.         ActiveDocument.Selection.Delete
  245.         ActiveDocument.Selection = CmtBlock
  246.     Else
  247.         MsgBox "This macro does not work on this type of file."
  248.     End If
  249.     
  250. End Sub
  251.  
  252.  
  253.  
  254. Sub AddRevisionMarks ( )
  255. 'DESCRIPTION: Adds comments to a file that describe the changes made.
  256.  
  257.     'This routine adds a new comment block to the top of a file, where the 
  258.     ' programmer can place revision marks to describe the changes made to the file.
  259.     'The rules this routine uses are as follows:
  260.     ' 1) Start at the top of the file.
  261.     ' 2) Scan through each line; if the current line starts with a comment,
  262.     '      advance to the next line..
  263.     ' 3) If we are currently in a group comment block, keep advancing until
  264.     '     the end of the block is found.
  265.     ' 4) If we are in a line item comment (e.g.: //, ', rem, etc), keep advancing
  266.     '     until a line that does not start with a comment is found.
  267.     '     By 'start with a comment', it is meant a line, where after
  268.     '     stripping off spaces and tabs from the beginning, the first set of
  269.     '     characters is not a comment delimiter.
  270.     ' 5) Insert a blank line; this allows the next invocation of this macro
  271.     '     to place the newer revision mark before all others.
  272.     ' 6) Insert the revision block.
  273.  
  274.     'Change this to the programmer's name for a default.
  275.     DefaultUserName = "..."
  276.  
  277.     'Because the user may not have closed a comment (e.g. a /* without a */),
  278.     ' try to protect ourselves from an infinite loop...
  279.     BreakAfter = 10 'Max number of lines to look at scan before aborting
  280.     CurrentCount = 1
  281.  
  282.     BeginComment = "" 'The token for the specified language for the beginning
  283.                         ' of a comment.
  284.     EndComment = ""   'Same, except for the end of a comment.
  285.     EveryLine = ""    'Does the comment mark need to be placed on every line
  286.                         ' (VBS, DEF types)?
  287.  
  288.     'First, make sure the active document is a text window
  289.     ' (Not really necessary, but good practice).
  290.     If ActiveDocument.Type = "Text" Then
  291.         TypeOfFile = FileType(ActiveDocument)
  292.     
  293.         'Set ourselves at the very top of the document.
  294.         'This also clears any selection made.
  295.         ActiveDocument.Selection.StartOfDocument
  296.         ActiveDocument.Selection.SelectLine
  297.         CurrText = ActiveDocument.Selection
  298.         CurrText = LTrim(CurrText)
  299.     
  300.         'All of the following do relatively the same thing, 
  301.         ' except they look for different comment types.
  302.         If TypeOfFile > 0 And TypeOfFile < 5 Then       'C/C++ family of code
  303.             ContSearch = True
  304.             BeginComment = "/*"
  305.             EndComment = "*/"
  306.             EveryLine = " "
  307.  
  308.             'In C/C++ style code, we need to look for a //;
  309.             '  if not found, then look for a /*.
  310.             Do
  311.                 ActiveDocument.Selection = CurrText
  312.                 If InStr(CurrText, "//") = 1 Then   'is a "//" available?
  313.                     ActiveDocument.Selection.SelectLine
  314.                     CurrText = LTrim(ActiveDocument.Selection) 'Remove whitespace.
  315.                     ContSearch = False   ' Looking at // style comments, 
  316.                                             'don't look for a /* style.
  317.                 Else
  318.                     Exit Do
  319.                 End If
  320.             Loop
  321.  
  322.             If ContSearch = False Then
  323.                 ActiveDocument.Selection.LineUp
  324.             End If
  325.  
  326.             'When the method ActiveDocument.Selection.SelectLine is called,
  327.             '  it is the same as when you click the mouse in the margin; it
  328.             '  selects the whole line, including the carriage return.
  329.             '  Because of this, the cursor comes down to the next line, which
  330.             '  can really confuse this algorithm. So in a number of places, 
  331.             '  you will see a grouping of LineUp/LineDown commands. By executing
  332.             '  these commands, the cursor is moved down, which clears the current
  333.             '  selection (including getting us past the carriage return),
  334.             '  then moves us back up, thus putting us on the same line. This
  335.             '  removesthe danger of skipping a line (which is what will
  336.             '  happen without the LineUp/LineDown combination).
  337.             If ContSearch = True Then
  338.                 ActiveDocument.Selection.StartOfDocument
  339.                 'Prime the loop with the first line.
  340.                 ActiveDocument.Selection.SelectLine
  341.                 CurrText = ActiveDocument.Selection           
  342.                 ActiveDocument.Selection.LineDown
  343.                 ActiveDocument.Selection.LineUp
  344.                 'Remove leading whitespace.
  345.                 CurrText = LTrim(CurrText)      
  346.                 'Does line start with a /*?              
  347.                 If InStr(CurrText,"/*") = 1 Then
  348.                     while (InStr(CurrText, "*/") = 0) And _
  349.                           (BreakAfter > CurrentCount)
  350.                         ActiveDocument.Selection.SelectLine
  351.                         CurrText = ActiveDocument.Selection
  352.                         CurrText = LTrim(CurrText)                              
  353.                         ActiveDocument.Selection.LineDown
  354.                         ActiveDocument.Selection.LineUp    
  355.                         CurrentCount = CurrentCount + 1
  356.                     wend
  357.                     If (BreakAfter > CurrentCount) Then
  358.                         'Exit the loop because the search has gone on for an 
  359.                         '  unreasonable number of lines.
  360.                         MsgBox "Could not find a closing comment mark"
  361.                     End If
  362.                 End If
  363.             End If
  364.  
  365.         'The code for these is really just a copy of that from the 
  366.         '  C/C++ section...
  367.           
  368.         ElseIf TypeOfFile = 5 Then                      'HTML code
  369.             BeginComment = "<!--"
  370.             EndComment = "-->"
  371.             EveryLine = "    "
  372.             If InStr(CurrText,"<!--") = 1 Then
  373.                 If InStr(CurrText,"-->") <> 0 Then
  374.                     ActiveDocument.Selection.LineDown
  375.                 Else
  376.                     Do
  377.                         ActiveDocument.Selection.SelectLine
  378.                         CurrText = ActiveDocument.Selection
  379.                         CurrText = Left(CurrText, Len(CurrText) - 2)
  380.                         ActiveDocument.Selection = CurrText + vbLf
  381.                         If InStr(CurrText, "-->") Then
  382.                             Exit Do
  383.                         End If
  384.                     Loop
  385.                 End If
  386.             End If 
  387.  
  388.         ElseIf TypeOfFile = 6 Then                      'VBS code
  389.             BeginComment = "'"
  390.             EndComment = "'"
  391.             EveryLine = "'"
  392.             Do
  393.                 ActiveDocument.Selection = CurrText
  394.                 If InStr(CurrText, "'") = 1 Or _
  395.                    InStr(LCase(CurrText), "Rem") = 1 Then
  396.                     ActiveDocument.Selection.SelectLine
  397.                     CurrText = LTrim(ActiveDocument.Selection)
  398.                     ContSearch = False
  399.                 Else
  400.                     Exit Do
  401.                 End If
  402.             Loop
  403.             If ContSearch = False Then
  404.                 ActiveDocument.Selection.LineUp
  405.             End If
  406.  
  407.         ElseIf TypeOfFile = 7 Then                      'DEF code
  408.             BeginComment = ";"
  409.             EndComment = ""
  410.             EveryLine = ";"
  411.             Do
  412.                 ActiveDocument.Selection = CurrText
  413.                 If InStr(CurrText, ";") = 1 Then
  414.                     ActiveDocument.Selection.SelectLine
  415.                     CurrText = LTrim(ActiveDocument.Selection)
  416.                     ContSearch = False
  417.                 Else
  418.                     Exit Do
  419.                 End If
  420.             Loop
  421.             If ContSearch = False Then
  422.                 ActiveDocument.Selection.LineUp
  423.             End If      
  424.         End If
  425.  
  426.         If TypeOfFile = 0 Then                          'Unknown type of code.
  427.             MsgBox("Unable to add revision marks. Unrecgonized file type")
  428.         ElseIf (CurrentCount < BreakAfter) Then
  429.             'The BeginComment, EveryLine, and EndComment were set as
  430.             ' avoid duplicating this section...
  431.             ' just insert the generalized block, with the comment markers.
  432.             ActiveDocument.Selection.StartOfLine(True)
  433.             'This is added with one assignment statement, which enables the user
  434.             ' to hit undo once, and remove the entire change.
  435.             ActiveDocument.Selection = vbLf + _
  436.             BeginComment + "***********************************" + vbLf + _
  437.             EveryLine    + " REVISION LOG ENTRY" + vbLf + _
  438.             EveryLine    + " Revision By: " + DefaultUserName + vbLf + _
  439.             EveryLine    + " Revised on " + CStr(Now) + vbLf + _
  440.             EveryLine    + " Comments: ..." + vbLf + _
  441.             EveryLine    + "***********************************" + _
  442.             EndComment + vbLf + vbLf
  443.         End If
  444.     End If
  445. End Sub
  446.  
  447.  
  448. Sub CloseExceptActive () 
  449. 'DESCRIPTION: Closes all editor windows except the current one.
  450.  
  451.     'Windows.Item(1) is always the currently active window. So to close all
  452.     ' the windows except the active one, keep looping until there is no 
  453.     ' longer a Windows.Item(2).
  454.     do while Windows.Count > 1
  455.         Windows.Item(2).Close(dsSaveChangesPrompt)
  456.     Loop
  457. End Sub
  458.  
  459.  
  460. Sub CommentOut ()
  461. 'DESCRIPTION: Comments out a selected block of text.
  462.     Dim win
  463.     set win = ActiveWindow
  464.     if win.type <> "Text" Then
  465.       MsgBox "This macro can only be run when a text editor window is active."
  466.     else
  467.         TypeOfFile = FileType(ActiveDocument)  
  468.         If TypeOfFile > 0 And TypeOfFile < 5 Then    'C & Java use the same 
  469.                                                         'style of comments.
  470.             ActiveDocument.Selection = "/*" + ActiveDocument.Selection + "*/"
  471.         ElseIf TypeOfFile = 5 Then
  472.             ActiveDocument.Selection = "<!-- " + ActiveDocument.Selection + " -->"
  473.         ElseIf TypeOfFile = 6 Or TypeOfFile = 7 Then
  474.             'There is no group comment like there is in the other file types, 
  475.             'so we need to iterate through each line, and prepend a ' to the line.
  476.             'Also, because VBS/DEF does not have a 'end the comment at this 
  477.             'particular column' delimiter, entire lines of code must be 
  478.             'commented out, not sections.
  479.             If TypeOfFile = 6 Then 
  480.                 CommentType = " ' "
  481.             Else
  482.                 CommentType = " ; "
  483.             End If
  484.      
  485.             StartLine = ActiveDocument.Selection.TopLine
  486.             EndLine = ActiveDocument.Selection.BottomLine
  487.             If EndLine < StartLine Then
  488.                 Temp = StartLine
  489.                 StartLine = EndLine
  490.                 EndLine = Temp
  491.             End If
  492.  
  493.             If EndLine = StartLine Then
  494.                 ActiveDocument.Selection = CommentType + ActiveDocument.Selection
  495.  
  496.             Else 
  497.                 For i = StartLine To EndLine
  498.                     ActiveDocument.Selection.GoToLine i
  499.                     ActiveDocument.Selection.SelectLine
  500.                     ActiveDocument.Selection = CommentType + _
  501.                         ActiveDocument.Selection
  502.                 Next
  503.             End If
  504.         Else
  505.             MsgBox("Unable to comment out the highlighted text" + vbLf + _
  506.                     "because the file type was unrecognized." + vbLf + _
  507.                     "If the file has not yet been saved, " + vbLf + _
  508.                     "please save it and try again.")
  509.         End If
  510.     End If
  511. End Sub
  512.  
  513.  
  514. Sub MultiplePaste () 
  515. 'DESCRIPTION: Performs a paste of what is on the clipboard a multiple number of times.
  516.  
  517.     NumPastes = InputBox("Number of pastes to make", "Multiple Paste Macro",_
  518.                          "1")
  519.     For i = 1 To CInt(NumPastes)
  520.         ActiveDocument.Selection.Paste
  521.         'Because the selection remains active, the following two lines
  522.         'clear the selection, while keeping the cursor in the same place.
  523.         ActiveDocument.Selection.LineUp
  524.         ActiveDocument.Selection.LineDown
  525.         ActiveDocument.Selection = vbLf    
  526.     Next
  527. End Sub
  528.  
  529.  
  530. Sub PrintAllOpenDocuments ()
  531. 'DESCRIPTION: Prints all open, active documents.
  532.  
  533.     'Small, quick macro, but it can be usefull.
  534.     for each doc in Application.Documents
  535.         Doc.PrintOut
  536.     next
  537. End Sub
  538.  
  539.  
  540. Sub PoundDefOut (ifndef)
  541.     If ifndef = true Then
  542.         PoundType = "#ifndef "
  543.     Else
  544.         PoundType = "#ifdef "
  545.     End If
  546.     
  547.     If FileType(ActiveDocument) <> 1 Then
  548.         MsgBox ("This macro only works on" + vbLf + _
  549.                 ".c, .cpp, .cxx, .h, .hpp, or .hxx files")
  550.     Else
  551.         ControlVarName = InputBox("What should the control variable be?" + _
  552.             vbLf + vbLf + "Example: #ifdef ControlVariable", PoundType + _
  553.             " out a section of code")
  554.         OK = True
  555.         If ValidId (ControlVarName) = False Then
  556.             Ok = False
  557.             MsgBox("""" + ControlVarName + """" + _ 
  558.                 " is not a valid C identifier." + _
  559.                 vbLf + "please re-run the macro with a valid C identifier")
  560.         End If
  561.         
  562.         
  563.         Sel = ActiveDocument.Selection
  564.         For i = 1 To Len(Sel) - 1
  565.             If Mid(Sel, i, 1) = vbLf Then
  566.                 Sel = Left(Sel,i) + vbTab + Right(Sel, Len(Sel)-i)
  567.             End If
  568.         Next
  569.         If ControlVarName <> "" And Ok = True Then
  570.             Sel = vbLf + PoundType + ControlVarName + vbLf + vbTab + Sel + _
  571.                 vbLf+ "#endif //" + ControlVarName
  572.             If Right(Sel,1) <> vbLf Then
  573.                 Sel = Sel + vbLf
  574.             End If
  575.             ActiveDocument.Selection = Sel
  576.         End If
  577.     End If
  578. End Sub
  579.  
  580. 'The next two macros are exactly the same, except one uses ifndef and the
  581. '  other ifdef. We recycle the same code and just use a different 
  582. '  preprocessor directive.
  583. Sub ifdefOut ()
  584. 'DESCRIPTION: #ifdef / #endif out a section of code.
  585.  
  586.     PoundDefOut (False)
  587. End Sub
  588.  
  589. Sub ifndefOut ()
  590. 'DESCRIPTION: #ifndef / #endif out a section of code.
  591.  
  592.     PoundDefOut (True)
  593. End Sub
  594.  
  595. 'Allows the user to make sure the current header file is included only once. 
  596. ' There are two ways to do this, using the #pragma once directive or 
  597. ' surrounding the entire file in a #ifndef/#endif structure. The first way
  598. ' is much cleaner, but it is VC++ specific, and therefore not portable. If 
  599. ' you plan on compiling your code with other compilers, use the 
  600. ' #ifndef/#endif method, otherwise, the #pragma once option is preferrable.
  601. Sub OneTimeInclude ()
  602. 'DESCRIPTION: Adds code to the current header file so it is included only once per c/cpp file.
  603.     
  604.     ext = ActiveDocument.Name
  605.     If ext = "" Then
  606.         If MsgBox("The file you are working with does not have a file extension." + _
  607.                 vbLF + "Are you sure this is a C/C++ header file?", 4) = vbCancel Then
  608.             Exit Sub
  609.         End If
  610.         ext = "nofilenamegiven.h"
  611.     End If
  612.     DocName = UCase(ext)
  613.     pos = Instr(ext, ".")
  614.     Do While pos <> 1
  615.         ext = Mid(ext, pos, (Len(ext) - pos + 1))
  616.         pos = Instr(ext, ".")
  617.     Loop
  618.     ext = LCase(ext)
  619.     pos = Instr(DocName, ".")
  620.     If ext = ".h" Or ext = ".hpp" Then
  621.         'Warn user that this will not work with a compiler other than VC++.
  622.         If MsgBox("This macro uses the Visual C++ dependant #pragma once" + _
  623.                 vbLf + "Is the source to be portable across compilers?", 4) _
  624.                 = 6 Then
  625.             ActiveDocument.Selection.StartOfDocument (False)
  626.             Examp = "__" + Left(DocName, pos - 1) + "_" + _
  627.                 UCase(Right(ext, len(ext) - 1)) + "__"
  628.             ControlVarName = InputBox("What should the control variable be?" _
  629.                 + vbLf + vbLf + "Example: #ifdef " + _
  630.                 Examp, "One time header include protection", Examp)
  631.             If ValidId (ControlVarName) = True Then
  632.                 ActiveDocument.Selection = "#ifndef " + ControlVarName + _
  633.                     vbLf + "#define " + ControlVarName + vbLf
  634.                 ActiveDocument.Selection.EndOfDocument(False)
  635.                 ActiveDocument.Selection = vbLf + "#endif //" + _ 
  636.                     ControlVarName
  637.             Else
  638.                 MsgBox(ControlVarName + " is not a valid c identifier." + _
  639.                 vbLf + "please re-run the macro with a valid C identifier")
  640.             End If
  641.         Else
  642.             ActiveDocument.Selection.StartOfDocument(False)
  643.             ActiveDocument.Selection = "#pragma once" + vbLf + vbLf
  644.         End If
  645.     Else
  646.         MsgBox("This macro can only be run on .h or .hpp files")
  647.     End If
  648. End Sub
  649.  
  650.  
  651.  
  652. 'Auto completion macro
  653. Dim previousSelection
  654. Dim completionWords
  655. Dim completionWordsIndex
  656.  
  657. Sub AddToCompletionWords (word)
  658.     ' If the word is already there, abort
  659.     if InStr(1, completionWords, " " & word & " ", 1) <> 0 Then
  660.         Exit Sub
  661.     End If
  662.  
  663.     completionWords = completionWords & word & " "
  664. End Sub
  665.  
  666. Function ExtractNextCompletionWord()
  667.     ExtractNextCompletionWord = ""
  668.  
  669.     ' If no words yet, go away
  670.     if Len(completionWords) <= 1 Then
  671.         Exit Function
  672.     End If
  673.     
  674.     ' Wrap to beginning if necessary
  675.     if completionWordsIndex > Len(completionWords) Then
  676.         completionWordsIndex = 2
  677.     End If
  678.  
  679.     ' Find next <space>
  680.     Dim newIndex
  681.     newIndex = InStr (completionWordsIndex, completionWords, " ", 0)
  682.     if newIndex = 0 Then
  683.         Exit Function
  684.     End If
  685.  
  686.     ExtractNextCompletionWord = Mid(completionWords, completionWordsIndex, _ 
  687.         newIndex-completionWordsIndex)
  688.     completionWordsIndex = newIndex+1        'Skip over <space>
  689. End Function
  690.  
  691. Sub FillCompletionWords (word)
  692.     ' Find all words in this file which match word, and
  693.     '  add them, space separated, into completionWords
  694.     previousSelection = word
  695.     completionWords = " "
  696.     completionWordsIndex = 2
  697.     dim sel
  698.     set sel = ActiveDocument.Selection
  699.  
  700.     Dim searchString
  701.     searchString = "\{^\![^a-zA-Z0-9]\}" & word
  702.     Dim firstTime
  703.     firstTime = True
  704.     Dim firstLine, firstCol
  705.     Do while sel.FindText (searchString, dsMatchBackward + dsMatchRegExp)
  706.         if firstTime Then
  707.             firstLine = sel.TopLine
  708.             firstCol = sel.CurrentColumn
  709.             firstTime = False
  710.         ElseIf firstLine = sel.TopLine And firstCol = sel.CurrentColumn Then
  711.             Exit Do        ' Jump out of loop before repeat
  712.         End If
  713.         sel.WordRight
  714.         sel.WordLeft dsExtend
  715.         AddToCompletionWords Trim(sel.text)
  716.         sel.Cancel
  717.     Loop
  718. End Sub
  719.  
  720. Function SuggestNextCompletionWord()
  721.     SuggestNextCompletionWord = True
  722.     Dim word
  723.     word = ExtractNextCompletionWord()
  724.     if word <> "" then
  725.         ActiveDocument.Selection = word
  726.         previousSelection = word
  727.     end if
  728. End Function
  729.  
  730. Sub AutoCompleteFromFile()
  731. 'DESCRIPTION: Looks through the active file, searching for the rest of the word that you began to type.
  732.     Dim doc
  733.     set doc = ActiveDocument
  734.  
  735.     ' Be sure active document is a text document
  736.     if doc Is Nothing Then
  737.         Exit Sub
  738.     elseif doc.Type <> "Text" Then
  739.         Exit Sub
  740.     End If
  741.  
  742.     ' Get word to be completed
  743.     Dim sel
  744.     set sel = doc.Selection
  745.     sel.Cancel
  746.     dim origLine, origCol
  747.     origLine = sel.TopLine
  748.     origCol = sel.CurrentColumn
  749.     sel.WordLeft dsExtend
  750.  
  751.     'If the cursor is sitting just to the right of a space, an infinite loop
  752.     'results. This bit of code protects from that:
  753.     if Right(sel, 1) = " " then
  754.         sel.CharRight
  755.         Exit Sub
  756.     end If
  757.  
  758.     if sel <> previousSelection Or completionWords = "" Then
  759.         FillCompletionWords sel
  760.         sel.MoveTo origLine, origCol
  761.         sel.WordLeft dsExtend
  762.     End If
  763.  
  764.     SuggestNextCompletionWord
  765.  
  766. End Sub
  767.