home *** CD-ROM | disk | FTP | other *** search
/ Total C++ 2 / TOTALCTWO.iso / borland / makehm.pak / MAKEHM.CPP < prev   
C/C++ Source or Header  |  1997-05-06  |  9KB  |  387 lines

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