[SPEC2DEF] Refactor to avoid parsing multiple times
[reactos.git] / sdk / tools / spec2def / spec2def.c
index 926cb32..324f884 100644 (file)
@@ -28,8 +28,29 @@ typedef struct
     int anArgs[30];
     unsigned int uFlags;
     int nNumber;
+    unsigned nStartVersion;
+    unsigned nEndVersion;
+    int bVersionIncluded;
 } EXPORT;
 
+#if 0 // Debug helper function
+void
+PrintExport(EXPORT *pexp)
+{
+    fprintf(stderr, "strName='%.*s'\n", pexp->strName.len, pexp->strName.buf);
+    fprintf(stderr, "strName='%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf);
+    fprintf(stderr, "nCallingConvention=%u\n", pexp->nCallingConvention);
+    fprintf(stderr, "nOrdinal=%u\n", pexp->nOrdinal);
+    fprintf(stderr, "nStackBytes=%u\n", pexp->nStackBytes);
+    fprintf(stderr, "nArgCount=%u\n", pexp->nArgCount);
+    fprintf(stderr, "uFlags=0x%x\n", pexp->uFlags);
+    fprintf(stderr, "nNumber=%u\n", pexp->nNumber);
+    fprintf(stderr, "nStartVersion=%u\n", pexp->nStartVersion);
+    fprintf(stderr, "nEndVersion=%u\n", pexp->nEndVersion);
+    fprintf(stderr, "bVersionIncluded=%u\n", pexp->bVersionIncluded);
+}
+#endif
+
 enum _ARCH
 {
     ARCH_X86,
@@ -509,7 +530,7 @@ PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
     const char *pcName = pstr->buf;
     int nNameLength = pstr->len;
     const char* pcDot, *pcAt;
-    char namebuffer[16];
+    char namebuffer[19];
 
     if ((nNameLength == 1) && (pcName[0] == '@'))
     {
@@ -803,17 +824,34 @@ Fatal(
     va_end(argptr);
 }
 
-int
-ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
+EXPORT *
+ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports)
 {
+    EXPORT *pexports;
     const char *pc, *pcLine;
-    int nLine;
+    int cLines, nLine;
     EXPORT exp;
-    int included, version_included;
+    int included;
     unsigned int i;
 
+    *cExports = 0;
+
     //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
 
+    /* Count the lines */
+    for (cLines = 1, pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), cLines++)
+    {
+        /* Nothing */
+    }
+
+    /* Allocate an array of EXPORT structures */
+    pexports = malloc(cLines * sizeof(EXPORT));
+    if (pexports == NULL)
+    {
+        fprintf(stderr, "ERROR: %s: failed to allocate EXPORT array of %u elements\n", pszSourceFileName, cLines);
+        return NULL;
+    }
+
     /* Loop all lines */
     nLine = 1;
     exp.nNumber = 0;
@@ -821,16 +859,32 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
     {
         pc = pcLine;
 
+        exp.strName.buf = NULL;
+        exp.strName.len = 0;
+        exp.strTarget.buf = NULL;
+        exp.strTarget.len = 0;
         exp.nArgCount = 0;
         exp.uFlags = 0;
         exp.nNumber++;
+        exp.nStartVersion = 0;
+        exp.nEndVersion = 0xFFFFFFFF;
+        exp.bVersionIncluded = 1;
 
         /* Skip white spaces */
         while (*pc == ' ' || *pc == '\t') pc++;
 
-        /* Skip empty lines, stop at EOF */
-        if (*pc == ';' || *pc <= '#') continue;
-        if (*pc == 0) return 0;
+        /* Check for line break or comment */
+        if ((*pc == '\r') || (*pc == '\n') ||
+            (*pc == ';') || (*pc == '#'))
+        {
+            continue;
+        }
+
+        /* On EOF we are done */
+        if (*pc == 0)
+        {
+            return pexports;
+        }
 
         /* Now we should get either an ordinal or @ */
         if (*pc == '@')
@@ -909,7 +963,6 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
 
         /* Handle options */
         included = 1;
-        version_included = 1;
         while (*pc == '-')
         {
             if (CompareToken(pc, "-arch="))
@@ -941,7 +994,7 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
                 const char *pcVersionStart = pc + 9;
 
                 /* Default to not included */
-                version_included = 0;
+                exp.bVersionIncluded = 0;
                 pc += 8;
 
                 /* Look if we are included */
@@ -981,11 +1034,14 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
                               "Invalid version range");
                     }
 
+                    exp.nStartVersion = version;
+                    exp.nEndVersion = endversion;
+
                     /* Now compare the range with our version */
                     if ((guOsVersion >= version) &&
                         (guOsVersion <= endversion))
                     {
-                        version_included = 1;
+                        exp.bVersionIncluded = 1;
                     }
 
                     /* Skip to next arch or end */
@@ -1042,7 +1098,7 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
         //fprintf(stderr, "info: Name:'%.10s'\n", pc);
 
         /* If arch didn't match ours, skip this entry */
-        if (!included || !version_included) continue;
+        if (!included) continue;
 
         /* Get name */
         exp.strName.buf = pc;
@@ -1235,11 +1291,12 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
             }
         }
 
-        OutputLine(fileDest, &exp);
+        pexports[*cExports] = exp;
+        (*cExports)++;
         gbDebug = 0;
     }
 
-    return 0;
+    return pexports;
 }
 
 void usage(void)
@@ -1265,7 +1322,8 @@ int main(int argc, char *argv[])
     const char* pszVersionOption = "--version=0x";
     char achDllName[40];
     FILE *file;
-    int result = 0, i;
+    unsigned cExports = 0, i;
+    EXPORT *pexports;
 
     if (argc < 2)
     {
@@ -1274,7 +1332,7 @@ int main(int argc, char *argv[])
     }
 
     /* Read options */
-    for (i = 1; i < argc && *argv[i] == '-'; i++)
+    for (i = 1; i < (unsigned)argc && *argv[i] == '-'; i++)
     {
         if ((strcasecmp(argv[i], "--help") == 0) ||
             (strcasecmp(argv[i], "-h") == 0))
@@ -1404,6 +1462,13 @@ int main(int argc, char *argv[])
     /* Zero terminate the source */
     pszSource[nFileSize] = '\0';
 
+    pexports = ParseFile(pszSource, file, &cExports);
+    if (pexports == NULL)
+    {
+        fprintf(stderr, "Failed to allocate memory for export data!\n");
+        return -1;
+    }
+
     if (pszDefFileName)
     {
         /* Open output file */
@@ -1415,7 +1480,13 @@ int main(int argc, char *argv[])
         }
 
         OutputHeader_def(file, pszDllName);
-        result = ParseFile(pszSource, file, OutputLine_def);
+
+        for (i = 0; i < cExports; i++)
+        {
+            if (pexports[i].bVersionIncluded)
+                 OutputLine_def(file, &pexports[i]);
+        }
+
         fclose(file);
     }
 
@@ -1430,7 +1501,13 @@ int main(int argc, char *argv[])
         }
 
         OutputHeader_stub(file);
-        result = ParseFile(pszSource, file, OutputLine_stub);
+
+        for (i = 0; i < cExports; i++)
+        {
+            if (pexports[i].bVersionIncluded)
+                OutputLine_stub(file, &pexports[i]);
+        }
+
         fclose(file);
     }
 
@@ -1445,10 +1522,18 @@ int main(int argc, char *argv[])
         }
 
         OutputHeader_asmstub(file, pszDllName);
-        result = ParseFile(pszSource, file, OutputLine_asmstub);
+
+        for (i = 0; i < cExports; i++)
+        {
+            if (pexports[i].bVersionIncluded)
+                OutputLine_asmstub(file, &pexports[i]);
+        }
+
         fprintf(file, "\n    END\n");
         fclose(file);
     }
 
-    return result;
+    free(pexports);
+
+    return 0;
 }