home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / utility / makehm / makehm.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  8.5 KB  |  375 lines

  1. // makehm.cpp : A simple utility to create .HM (Help Map) files from
  2. //              .H (resource header files).
  3. //
  4. // This is a part of the Microsoft Foundation Classes C++ library.
  5. // Copyright (C) 1992-1998 Microsoft Corporation
  6. // All rights reserved.
  7. //
  8. // This source code is only intended as a supplement to the
  9. // Microsoft Foundation Classes Reference and related
  10. // electronic documentation provided with the library.
  11. // See these sources for detailed information regarding the
  12. // Microsoft Foundation Classes product.
  13.  
  14. //  This utility creates a .HM file from a header file (usually
  15. //  resource.h) which allows one to maintain the help mappings
  16. //  without a lot of manual effort on the part of the programmer
  17. //  or help author.
  18. //
  19. //  This is done by naming convention, the naming convention used
  20. //  being that normally accepted as standard Windows and MFC
  21. //  programming practices.
  22.  
  23. #include <ctype.h>
  24. #include <afxcoll.h>    // also includes <afx.h>
  25.  
  26. #ifdef _DEBUG
  27. #undef THIS_FILE
  28. static char BASED_CODE THIS_FILE[] = __FILE__;
  29. #endif
  30.  
  31. #define SIGNON_VER 6
  32. #define SIGNON_REV 0
  33.  
  34. /////////////////////////////////////////////////////////////////////////////
  35.  
  36. void UsageErr(const char* szErrorMessage = NULL,
  37.               const char* szErrorParam = NULL)
  38. {
  39.     fprintf(stderr,
  40.         "\nMicrosoft (R) Help Maintainence Utility   Version %d.%02d\n"
  41.         "Copyright (c) Microsoft Corp. 1992-1998. All rights reserved.\n\n",
  42.         SIGNON_VER, SIGNON_REV);
  43.  
  44.     if (szErrorMessage != NULL)
  45.     {
  46.         fprintf(stderr, "makehm: error: ");
  47.         fprintf(stderr, szErrorMessage, szErrorParam);
  48.         fprintf(stderr, ".\n\n");
  49.     }
  50.  
  51.     fprintf(stderr, "makehm usage:\n\n"
  52.     "  makehm <from>,<to>,<add>... <resource.h> [output.hm]\n"
  53.     "\n"
  54.     "    <from>,<to>,<add> fields must appear as one argument and\n"
  55.     "       are separated by commas.  A set of these arguments may\n"
  56.     "       appear more than once.\n"
  57.     "    <from> - identifies the symbol prefix to map from (ie. ID_)\n"
  58.     "    <to>   - identifies the symbol prefix to map to (ie. HID_)\n"
  59.     "    <add>  - identifies a numeric offset to be used (ie. 0x10000)\n"
  60.     "\n"
  61.     "    <resource.h> - identifies the input header file (ie. resource.h).\n"
  62.     "    [output.hm] - identifies the output help map file.  If not\n"
  63.     "       supplied, output is written to stdout.\n");
  64.  
  65.     exit(1);
  66. }
  67.  
  68. /////////////////////////////////////////////////////////////////////////////
  69.  
  70. class CLineFile : public CStdioFile
  71. {
  72. public:
  73.     BOOL ReadLine(CString& stringLine);
  74.     void WriteLine(const CString& stringLine);
  75.     void SafeOpen(const CString& string, UINT nStyleFlags);
  76. };
  77.  
  78. BOOL CLineFile::ReadLine(CString& str)
  79. {
  80.     UINT nMax = 512;
  81.     for (;;)
  82.     {
  83.         LONG pos = GetPosition();
  84.         if (!ReadString(str.GetBuffer(nMax), nMax))
  85.             return FALSE;
  86.         str.ReleaseBuffer();
  87.         if (str.GetLength() < (int)nMax-1)
  88.             return TRUE;
  89.         nMax += 128;
  90.         Seek(pos, CFile::begin);
  91.     }
  92.     ASSERT(FALSE);
  93. }
  94.  
  95. void CLineFile::WriteLine(const CString& str)
  96. {
  97.     ASSERT(str[str.GetLength()-1] == '\n');
  98.     WriteString(str);
  99. }
  100.  
  101. void CLineFile::SafeOpen(const CString& name, UINT nStyleFlags)
  102. {
  103.     BOOL fSuccess = Open(name, nStyleFlags, 0);
  104.     if (!fSuccess)
  105.         UsageErr("unable to open file \"%s\"", name);
  106. }
  107.  
  108. /////////////////////////////////////////////////////////////////////////////
  109.  
  110. BOOL IsValidSymbol(const char* psz)
  111. {
  112.     if (!__iscsymf(*psz))
  113.         return FALSE;
  114.  
  115.     ASSERT(*psz != 0);
  116.     ++psz;
  117.     while (*psz)
  118.     {
  119.         if (!__iscsym(*psz))
  120.             return FALSE;
  121.         ++psz;
  122.     }
  123.     return TRUE;
  124. }
  125.  
  126. #define isodigit(i) ('0' <= (i) && (i) <= '7')
  127.  
  128. BOOL IsValidValue(const char* psz, DWORD& dwValue)
  129. {
  130.     if (*psz == 0 || !isdigit(*psz))
  131.         return FALSE;
  132.  
  133.     DWORD dw = 0;
  134.     if (psz[0] == '0' && (psz[1] == 'x' || psz[1] == 'X'))
  135.     {
  136.         if (psz[1] == 0)
  137.             return FALSE;
  138.         psz += 2;
  139.         while (isxdigit(*psz))
  140.         {
  141.             dw *= 16;
  142.             dw += isdigit(*psz) ? *psz - '0' : 10 + (*psz|0x20) - 'a';
  143.             ++psz;
  144.         }
  145.     }
  146.     else if (psz[0] == '0')
  147.     {
  148.         while (isodigit(*psz))
  149.         {
  150.             dw *= 8;
  151.             dw += *psz - '0';
  152.             ++psz;
  153.         }
  154.     }
  155.     else
  156.     {
  157.         while (isdigit(*psz))
  158.         {
  159.             dw *= 10;
  160.             dw += *psz - '0';
  161.             ++psz;
  162.         }
  163.     }
  164.  
  165.     if (*psz != 0)
  166.         return FALSE;
  167.  
  168.     dwValue = dw;
  169.     return TRUE;
  170. }
  171.  
  172. /////////////////////////////////////////////////////////////////////////////
  173.  
  174. CPtrArray aMap;
  175.  
  176. struct CMapInfo
  177. {
  178.     char* pszPrefixFrom;
  179.     char* pszPrefixTo;
  180.     DWORD dwAddTo;
  181. };
  182.  
  183. void AddToMap(char* pszArg)
  184. {
  185.     ASSERT(pszArg != NULL);
  186.     char* psz = _strdup(pszArg);
  187.     if (psz == NULL)
  188.     {
  189.         AfxThrowMemoryException();
  190.         ASSERT(FALSE);
  191.     }
  192.     ASSERT(strchr(psz, ',') != NULL);
  193.  
  194.     char* pszPrefixFrom;
  195.     char* pszPrefixTo;
  196.     char* pszAddTo;
  197.     DWORD dwAddTo;
  198.     CMapInfo* pInfo;
  199.  
  200.     // parse each field out of the argument.
  201.     pszPrefixFrom = strtok(psz, ",");
  202.     pszPrefixTo = strtok(NULL, ",");
  203.     if (pszPrefixTo == NULL)
  204.         goto ParmError;
  205.     pszAddTo = strtok(NULL, ",");
  206.     if (pszAddTo == NULL)
  207.         goto ParmError;
  208.  
  209.     // make sure they are valid symbols/values.
  210.     if (!IsValidSymbol(pszPrefixFrom) || !IsValidSymbol(pszPrefixTo))
  211.         goto ParmError;
  212.     if (!IsValidValue(pszAddTo, dwAddTo))
  213.         goto ParmError;
  214.  
  215.     // add them to the map.
  216.     pInfo = new CMapInfo;
  217.     ASSERT(pInfo);
  218.     pInfo->pszPrefixFrom = pszPrefixFrom;
  219.     pInfo->pszPrefixTo = pszPrefixTo;
  220.     pInfo->dwAddTo = dwAddTo;
  221.     aMap.Add(pInfo);
  222.     return;
  223.  
  224. ParmError:
  225.     UsageErr("parameter \"%s\" not correctly formed.", pszArg);
  226.     ASSERT(FALSE);
  227. }
  228.  
  229. CMapInfo* FindInMap(const char* psz)
  230. {
  231.     ASSERT(psz != NULL);
  232.     ASSERT(*psz != 0);
  233.     int nMax = aMap.GetSize();
  234.     for (int i = 0; i < nMax; i++)
  235.     {
  236.         CMapInfo* pInfo = (CMapInfo*)aMap.GetAt(i);
  237.         size_t nLen = strlen(pInfo->pszPrefixFrom);
  238.         if (strncmp(pInfo->pszPrefixFrom, psz, nLen) == 0)
  239.             return pInfo;
  240.     }
  241.     return NULL;
  242. }
  243.  
  244. /////////////////////////////////////////////////////////////////////////////
  245.  
  246. BOOL
  247. MapNameValue(const char* pszName, CString& strNewName, DWORD& dwValue)
  248. {
  249.     CMapInfo* pInfo = FindInMap(pszName);
  250.     if (pInfo == NULL)
  251.         return FALSE;
  252.  
  253.     CString strName = pszName;
  254.     strNewName = (CString)pInfo->pszPrefixTo +
  255.         strName.Right(strName.GetLength()-strlen(pInfo->pszPrefixFrom));
  256.     dwValue += pInfo->dwAddTo;
  257.     return TRUE;
  258. }
  259.  
  260. CString StringFromDword(DWORD dwValue)
  261. {
  262.     char buf[sizeof "0x12345678"];
  263.     sprintf(buf, "0x%lX", dwValue);
  264.     return CString(buf);
  265. }
  266.  
  267. BOOL MapLine(CString& strLine)
  268. {
  269.     static char szWhiteSpace1[] = "\t ";
  270.     static char szWhiteSpace2[] = "\t\n ";
  271.     static char szDefine[] = "#define";
  272.  
  273.     char* pszCopy = _strdup(strLine);
  274.     if (pszCopy == NULL)
  275.     {
  276.         AfxThrowMemoryException();
  277.         ASSERT(FALSE);
  278.     }
  279.  
  280.     char* psz;
  281.     char* pszSymbol;
  282.     char* pszValue;
  283.     DWORD dwValue;
  284.     CString strNewName;
  285.  
  286.     // '//{{NOHELP}}' can be placed on the line and it will not be included
  287.     if (strstr(strLine, "//{{NOHELP}}") != NULL)
  288.         goto RetFalse;
  289.  
  290.     psz = strtok(pszCopy, szWhiteSpace1);
  291.     if (psz == NULL)
  292.         goto RetFalse;
  293.     if (strcmp(psz, szDefine) != 0)
  294.         goto RetFalse;
  295.     pszSymbol = strtok(NULL, szWhiteSpace1);
  296.     if (pszSymbol == NULL)
  297.         goto RetFalse;
  298.     pszValue = strtok(NULL, szWhiteSpace2);
  299.     if (pszValue == NULL)
  300.         goto RetFalse;
  301.  
  302.     if (!IsValidSymbol(pszSymbol))
  303.         goto RetFalse;
  304.     if (!IsValidValue(pszValue, dwValue))
  305.         goto RetFalse;
  306.     if (!MapNameValue(pszSymbol, strNewName, dwValue))
  307.         goto RetFalse;
  308.  
  309.     //BLOCK: format output line
  310.     {
  311.         CString strPad(' ', 40-strNewName.GetLength());
  312.         if (strPad.IsEmpty())
  313.             strPad = '\t';
  314.         strLine = strNewName + strPad + StringFromDword(dwValue) + "\n";
  315.     }
  316.  
  317.     ASSERT(pszCopy != NULL);
  318.     free(pszCopy);
  319.     return TRUE;
  320.  
  321. RetFalse:
  322.     ASSERT(pszCopy != NULL);
  323.     free(pszCopy);
  324.     return FALSE;
  325. }
  326.  
  327. /////////////////////////////////////////////////////////////////////////////
  328.  
  329. int main(int argc, char** argv)
  330. {
  331.     // add symbol mappings to the map.
  332.     BOOL fAddedToMap = FALSE;
  333.     for (int i = 1; i < argc && strchr(argv[i], ',') != NULL; i++)
  334.     {
  335.         AddToMap(argv[i]);
  336.         fAddedToMap = TRUE;
  337.     }
  338.  
  339.     // must only have 1-2 parms left on command line.
  340.     if (!fAddedToMap || i < argc-2 || i > argc-1)
  341.     {
  342.         UsageErr(NULL, NULL);
  343.         ASSERT(FALSE);
  344.     }
  345.  
  346.     // open input file.
  347.     CLineFile fileIn;
  348.     fileIn.SafeOpen(argv[i], CLineFile::modeRead);
  349.  
  350.     // open/hook up output file.
  351.     CLineFile fileOut;
  352.     if (i+1 < argc)
  353.         fileOut.SafeOpen(argv[i+1], CLineFile::modeWrite | CLineFile::modeCreate);
  354.     else
  355.         fileOut.m_pStream = stdout;
  356.  
  357.     // process the file.
  358.     CString strLine;
  359.     while (fileIn.ReadLine(strLine))
  360.     {
  361.         if (MapLine(strLine))
  362.         {
  363.             fileOut.WriteLine(strLine);
  364.         }
  365.     }
  366.  
  367.     // close files.
  368.     fileIn.Close();
  369.     fileOut.Close();
  370.  
  371.     return 0;
  372. }
  373.  
  374. /////////////////////////////////////////////////////////////////////////////
  375.