home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / addins / api2help / apisplit.cpp < prev    next >
C/C++ Source or Header  |  1998-04-02  |  13KB  |  386 lines

  1. // Copyright (C) 1992-1998 Microsoft Corporation
  2. // All rights reserved.
  3.  
  4.  
  5. //This code is the basis for which the add-in to MSDevStudio
  6. //      for generating help files will stem. As of now it splits apart
  7. //      the prototype for a function
  8.  
  9. //This will work on almost every function declaration
  10. //      1)      DO NOT use on function pointer declarations. For example:
  11. //                              "DWORD (CALLBACK* Get)(LPOLESTREAM, void FAR*, DWORD);"
  12. //                      will fail. The parser gets confused on the (CALLBACK* Get).
  13. //      2)      The question arises as to which which do you run this macro on,
  14. //                              in the header declaration, or in the actual source code.
  15. //                              If you are generating help for a function not in a class, it
  16. //                              is probably best to run it on the header file declaration.
  17. //                              If the function is in a class, try to run it on the source
  18. //                              declaration     because the parser can detect the class scoping
  19. //                              (although, as of right now parses this class scoping, but does
  20. //                              nothing with it, except storing it into an array).
  21. //      3)      Many OLE 2 declarations are declared with macros,
  22. //                              WINOLEAPI_(BOOL) OleIsRunning(LPOLEOBJECT pObject);
  23. //                              the parser is fine with this as long as there are no spaces in
  24. //                              between the WINOLEAPI_ and (BOOL).
  25. //      4)      The parser gets confused if the prototype is something like:
  26. //                      void foo(CArray<CObject, CObject> bar); This happens when there is
  27. //                      a template in the parameter list and a comma appears within this
  28. //                      template declaration. The parser gets confused and tries to set
  29. //                      each as a parameter, ie CArray<CObject is one parameter, and
  30. //                      CObject> bar is another.
  31.  
  32.  
  33.  
  34. #include <stdafx.h>
  35. #include <afxtempl.h>
  36. #include <fstream.h>
  37. #include "resource.h"
  38. #include "apisplit.h"
  39.  
  40. //The following value is described in the comment for GetReturnType
  41. #define DEFAULT_RETURN 1
  42.  
  43. inline void WriteString(CString strStr, CFile& file)
  44. { file.Write(strStr, strStr.GetLength()); }
  45.  
  46. inline void WriteString(int nIDS, CFile& file)
  47. {
  48.     CString strStringToWrite;
  49.     strStringToWrite.LoadString(nIDS);
  50.     WriteString(strStringToWrite, file);
  51. }
  52.  
  53. void GenerateHTML(CString strHTMLPath, CString strClassFunctionName,
  54.         CString strFunctionName,
  55.         CArray<CString,CString>& Parameters,
  56.         CArray<CString,CString>& ParameterNames, CString strReturn)
  57. {
  58.     CFile Stream(strHTMLPath,
  59.             CFile::modeCreate|CFile::modeWrite|CFile::shareExclusive);
  60.     WriteString(IDS_HTML1, Stream);
  61.     WriteString(strFunctionName, Stream);
  62.     WriteString(IDS_HTML2, Stream);
  63.     WriteString(strClassFunctionName, Stream);
  64.     WriteString(IDS_HTML3, Stream);
  65.  
  66.     WriteString(strReturn+" "+strFunctionName,Stream);
  67.  
  68.     WriteString(IDS_HTML4, Stream);
  69.  
  70.     if (Parameters.GetSize() != 0)
  71.     {
  72.         for (int i = 0 ; i < Parameters.GetSize()-1 ; i++)
  73.         {
  74.             WriteString(IDS_HTML5, Stream);
  75.             WriteString(Parameters.GetAt(i), Stream);
  76.             WriteString(IDS_HTML6, Stream);
  77.         }
  78.         WriteString(IDS_HTML5, Stream);
  79.         WriteString(Parameters.GetAt(Parameters.GetSize()-1), Stream);
  80.         WriteString(IDS_HTML7, Stream);
  81.     }
  82.     else
  83.         WriteString(IDS_HTML8, Stream);
  84.  
  85.     WriteString(IDS_HTML9, Stream);
  86.  
  87.     for (int i = 0 ; i < ParameterNames.GetSize() ;i++)
  88.     {
  89.         WriteString(IDS_HTML10, Stream);
  90.         WriteString(ParameterNames.GetAt(i), Stream);
  91.         WriteString(IDS_HTML11, Stream);
  92.     }
  93.     //For some reason, the following <dt></dt> sequence is needed to keep
  94.     //  things straight.in the resulting HTML
  95.     WriteString(IDS_HTML12, Stream);
  96. }
  97.  
  98. void GenerateHelpFile(CString strRTFPath, CString strClassFunctionName,
  99.                       CString strFunctionName,
  100.                       CArray<CString,CString>& Parameters,
  101.                       CArray<CString,CString>& ParameterNames,
  102.                       CString strReturn, CString ContextID, CString TopicName)
  103. {
  104.     CString sStringToWrite;
  105.     CFile Stream(strRTFPath,
  106.             CFile::modeCreate|CFile::modeWrite|CFile::shareExclusive);
  107.  
  108.     WriteString(IDS_RTF1, Stream);
  109.     WriteString(IDS_RTF2, Stream);
  110.     WriteString(IDS_RTF3, Stream);
  111.  
  112.     //Send the context ID for the page being generated
  113.     WriteString(ContextID, Stream);
  114.     //Dump secondary help header
  115.     WriteString(IDS_RTF4, Stream);
  116.     WriteString("SIMPLE Help Topic 1", Stream);
  117.  
  118.     //More header info
  119.     WriteString(IDS_RTF5, Stream);
  120.  
  121.     //Dump the name this is known as in help topics.index dialog
  122.     WriteString(TopicName, Stream);
  123.  
  124.     //Output prototype dependant information
  125.     WriteString(IDS_RTF6, Stream);
  126.     WriteString(strClassFunctionName, Stream);
  127.     WriteString(IDS_RTF7, Stream);
  128.  
  129.     WriteString(strReturn+" "+strFunctionName+"(\n", Stream);
  130.     WriteString("\\par ", Stream);
  131.  
  132.     if (Parameters.GetSize() != 0)
  133.     {
  134.         for (int i = 0 ; i < Parameters.GetSize()-1 ; i++)
  135.         {
  136.             WriteString("  "+Parameters.GetAt(i)+",\n", Stream);
  137.             WriteString("\\par\n", Stream);
  138.         }
  139.         WriteString("  "+Parameters.GetAt(Parameters.GetSize()-1), Stream);
  140.     }
  141.  
  142.     WriteString(IDS_RTF8, Stream);
  143.  
  144.     for (int i = 0 ; i < ParameterNames.GetSize() ;i++)
  145.     {
  146.         WriteString(ParameterNames.GetAt(i)+"\n", Stream);
  147.         WriteString(IDS_RTF9, Stream);
  148.     }
  149.     WriteString(IDS_RTF10, Stream);
  150.     Stream.Close();
  151. }
  152.  
  153. //Because double spaces only get in the way, this routine removes them.
  154. //It also removes spaces around '::' so that we can find scope resolution
  155. void RemoveUnnecessary(CString& str)
  156. {
  157.     //First, strip out all those pesky, unwanted double spaces
  158.     str.TrimLeft();
  159.     str.TrimRight();
  160.     int nLoc = str.Find("  ");
  161.     while (nLoc > 0)
  162.     {
  163.         str = str.Left(nLoc) + str.Right(str.GetLength()-nLoc-1);
  164.         nLoc = str.Find("  ");
  165.     }
  166.  
  167.     //Now get rid of and ' ::' or ':: '
  168.     nLoc = str.Find(" ::");
  169.     while(nLoc > 0)
  170.     {
  171.         str = str.Left(nLoc) + str.Right(str.GetLength()-nLoc-1);
  172.         nLoc = str.Find(" ::");
  173.     }
  174.     nLoc = str.Find(":: ");
  175.     while(nLoc > 0)
  176.     {
  177.         str = str.Left(nLoc+2) + str.Right(str.GetLength()-nLoc-3);
  178.         nLoc = str.Find(":: ");
  179.     }
  180. }
  181.  
  182. void GetFunctAndScope(CString& strFuncName, CArray<CString,CString>& Scoping,
  183.                       CString& strNewFunc)
  184. {
  185.     strNewFunc = strFuncName;
  186.     int nLoc = strNewFunc.Find("::");
  187.     while (nLoc > 0)
  188.     {
  189.         Scoping.Add(strNewFunc.Left(nLoc));
  190.         strNewFunc = strNewFunc.Right(strNewFunc.GetLength()-nLoc-2);
  191.         nLoc = strNewFunc.Find("::");
  192.     }
  193. }
  194.  
  195. void ConvertWSToSpace (CString& str)
  196. {
  197.     //To fix the problem of when there is a comment describing parameters,
  198.     //      the first step is to scan the string, and see if there are any '//'
  199.     int nLoc = str.Find("//");
  200.     while (nLoc != -1)
  201.     {
  202.         //There is a '//', so we then take the string from there to the
  203.         //  end of the string, and find a '\n'
  204.         CString strComment = str.Right(str.GetLength()-nLoc);
  205.         str = str.Left(nLoc);
  206.         //within comment, search for the '\n'
  207.         int nCRLoc = strComment.Find('\n');
  208.         if (nCRLoc != -1)
  209.         {
  210.             CString strDecommented = strComment.Right(
  211.                     strComment.GetLength()-nCRLoc);
  212.             str += strDecommented;
  213.             //An enhancement would be to save this comment, and use it
  214.             //  to describe the parameter in the help file
  215.             nLoc = str.Find("//");
  216.         }
  217.         else
  218.         {
  219.             nLoc = -1;
  220.         }
  221.     }
  222.  
  223.     //Next, a search for the old style comments (/**/) is performed
  224.     nLoc = str.Find("/*");
  225.     while(nLoc != -1)
  226.     {
  227.         CString strComment = str.Right(str.GetLength()-nLoc);
  228.         str = str.Left(nLoc);
  229.         //within the comment, search for the closing '*/'
  230.         int nEndComm = strComment.Find("*/");
  231.         if (nEndComm != -1)
  232.         {
  233.             CString strDecommented = strComment.Right(
  234.                     strComment.GetLength()-nEndComm-2);
  235.             str += strDecommented;
  236.             //An enhancement would be to save this comment,
  237.             //  and use it to describe the parameter in the help file
  238.             nLoc = str.Find("/*");
  239.         }
  240.         else
  241.         {
  242.             nLoc = -1;
  243.         }
  244.     }
  245.     nLoc = str.Find("\t");
  246.     while(nLoc != -1)
  247.     {
  248.         char foo = str.GetAt(nLoc);
  249.         str.SetAt(nLoc, ' ');
  250.         nLoc = str.Find("\t");
  251.  
  252.     }
  253.     nLoc = str.Find("\n");
  254.     while(nLoc != -1)
  255.     {
  256.         char foo = str.GetAt(nLoc);
  257.         str.SetAt(nLoc, ' ');
  258.         nLoc = str.Find("\n");
  259.     }
  260.     /*for (int i = 0 ; i < str.GetLength()-1 ; i++)
  261.         if ((str[i] == '\t') || (str[i] == '\n'))
  262.             str.SetAt(i, ' ');*/
  263. }
  264.  
  265. void GetReturnType(CString& str, CArray<CString,CString>& ReturnsArray,
  266.                    CString& strSuggested, int nAppendStar)
  267. {
  268.     //There are many conflicts that could arise from
  269.     //      finding the return type, for example look at the prototype
  270.     //      from the windows header files for FreeLibrary:
  271.     //      WINBASEAPI BOOL WINAPI FreeLibrary(HMODULE hLibModule);
  272.     //  If we start at FreeLibrary and scan backwards for the first
  273.     //      word, we have WINAPI as the return type. If we start at
  274.     //      the beginning of the line and scan foreward for the first
  275.     //      word, we have WINBASEAPI as the return type. Things could
  276.     //      also get more complicated, we could start throwing FAR's,
  277.     //      _declspec's, and much more (static _declspec BOOL FAR foo(char*))
  278.     //  The way this is remedied is as follows:
  279.     //      1) Count the number of items that appears before the function name
  280.     //      2) if Count == 0, no return type is assumed
  281.     //               if Count == 1, use the found return type
  282.     //               if Count >= 2, use the DEFAULT_RETURN word as the return type
  283.     //      If the wrong word is grabbed, it is trivial to change it in the
  284.     //      help file, but under most circumstances this should work.*/
  285.  
  286.     //we know the string is of the form:  words words ...  funcname
  287.     str = str.Left(str.ReverseFind(' '));
  288.     str.TrimRight();
  289.  
  290.     if (str.GetLength() != 0)
  291.     {
  292.         int nEndOfItem = str.Find(' ');
  293.         while ((str.GetLength() != 0) && (nEndOfItem != -1))
  294.         {
  295.             ReturnsArray.Add(str.Left(nEndOfItem));
  296.  
  297.             str = str.Right(str.GetLength()-nEndOfItem);
  298.             str.TrimLeft();
  299.             str.TrimRight();
  300.             nEndOfItem = str.Find(' ');
  301.         }
  302.         ReturnsArray.Add(str);
  303.  
  304.         //Right now there could possibly be a problem with pointers, if the
  305.         //      prototype is of the form HWND *foo(...) the pointer is attached to
  306.         //  the function name, when in actuality the '*' belongs with HWND.
  307.         //  Also there is the case when the prototype is HWND * foo(...), it
  308.         //  ends up that * is viewed as a return type, that is fixed up here.
  309.         for (int i = 0 ; i < ReturnsArray.GetSize() ; i++)
  310.         {
  311.             //Check to see if the element is a '*'
  312.             if (ReturnsArray.GetAt(i) == "*")
  313.             {
  314.                 //Delete it...
  315.                 ReturnsArray.RemoveAt(i);
  316.                 //Change old value before it
  317.                 ReturnsArray.SetAt(i-1, ReturnsArray.GetAt(i-1) + "*");
  318.             }
  319.         }
  320.  
  321.         //Check for the HWND *foo(...) case
  322.         for (i = nAppendStar ; i > 0 ; i--)
  323.             ReturnsArray.SetAt(ReturnsArray.GetSize()-1,
  324.                     ReturnsArray.GetAt(ReturnsArray.GetSize()-1) + " *");
  325.  
  326.         //Here we decide which value we use as the return type,
  327.         //      there probably is a better way of calculating this, but that
  328.         //  will be
  329.         //      left until later.
  330.         if (ReturnsArray.GetSize() == 1)
  331.             strSuggested = ReturnsArray.GetAt(0);
  332.         else
  333.         {
  334.             //If DEFAULT_RETURN is greater than the actual number of possible
  335.             //  return types, then give back the last possible one
  336.             if (DEFAULT_RETURN > ReturnsArray.GetSize())
  337.                 strSuggested = ReturnsArray.GetAt(ReturnsArray.GetSize()-1);
  338.             else
  339.                 strSuggested = ReturnsArray.GetAt(DEFAULT_RETURN);
  340.         }
  341.     }
  342. }
  343.  
  344. void GetListOfParamNames(CArray<CString,CString>& ParamList,
  345.                 CArray<CString,CString>& ParamNames)
  346. {
  347.     for (int i = 0 ; i < ParamList.GetSize() ; i++)
  348.     {
  349.         CString strTemp = ParamList.GetAt(i);
  350.         strTemp = strTemp.Right(strTemp.GetLength()-strTemp.ReverseFind(' ')-1);
  351.         while (strTemp[0] == '*')
  352.             strTemp = strTemp.Right(strTemp.GetLength()-1);
  353.         ParamNames.Add(strTemp);
  354.     }
  355. }
  356.  
  357. int GetParameters(CString& strParameters, CString& strPrototype,
  358.                 CArray<CString,CString>& ParamList)
  359. {
  360.     //Start off by getting to the end of the argument list
  361.     strParameters = strPrototype.Left(strPrototype.ReverseFind(')'));
  362.     strParameters.TrimRight();
  363.  
  364.     int nBeginningOfParameters = strParameters.ReverseFind('(');
  365.     strParameters = strParameters.Right(strParameters.GetLength()-
  366.             nBeginningOfParameters-1);
  367.     strParameters.TrimLeft();
  368.  
  369.     //now pull off each parameter
  370.     if (strParameters.GetLength() != 0)
  371.     {
  372.         int nComma = strParameters.Find(',');
  373.         while (nComma != -1)
  374.         {
  375.             ParamList.Add(strParameters.Left(nComma));
  376.             strParameters = strParameters.Right(strParameters.GetLength()-
  377.                     nComma-1);
  378.             strParameters.TrimLeft();
  379.             strParameters.TrimRight();
  380.             nComma = strParameters.Find(',');
  381.         }
  382.         ParamList.Add(strParameters);
  383.     }
  384.     return nBeginningOfParameters;
  385. }
  386.