[SPEC2DEF] Improve error output
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 17 Aug 2019 18:32:15 +0000 (20:32 +0200)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sun, 15 Sep 2019 10:06:47 +0000 (12:06 +0200)
sdk/tools/spec2def/spec2def.c

index 65fa07c..f1b5d78 100644 (file)
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdarg.h>
 
 #ifdef _MSC_VER
 #define strcasecmp(_String1, _String2) _stricmp(_String1, _String2)
@@ -711,6 +712,73 @@ OutputLine_def(FILE *fileDest, EXPORT *pexp)
     return 1;
 }
 
+void
+Fatalv(
+    const char* filename,
+    unsigned nLine,
+    char *pcLine,
+    char *pc,
+    size_t errorlen,
+    const char *format,
+    va_list argptr)
+{
+    unsigned i, errorpos, len;
+    const char* pcLineEnd;
+
+    /* Get the length of the line */
+    pcLineEnd = strpbrk(pcLine, "\r\n");
+    len = pcLineEnd - pcLine;
+
+    if (pc == NULL)
+    {
+        pc = pcLine + len - 1;
+        errorlen = 1;
+    }
+
+    errorpos = (unsigned)(pc - pcLine);
+
+    /* Output the error message */
+    fprintf(stderr, "ERROR: (%s:%u:%u): ", filename, nLine, errorpos);
+    vfprintf(stderr, format, argptr);
+    fprintf(stderr, "\n");
+
+    /* Output the line with the error */
+    fprintf(stderr, "> %.*s\n", len, pcLine);
+
+    if (errorlen == 0)
+    {
+        errorlen = TokenLength(pc);
+    }
+
+    for (i = 0; i < errorpos + 2; i++)
+    {
+        fprintf(stderr, " ");
+    }
+    for (i = 0; i < errorlen; i++)
+    {
+        fprintf(stderr, "~");
+    }
+    fprintf(stderr, "\n");
+    exit(-1);
+}
+
+void
+Fatal(
+    const char* filename,
+    unsigned nLine,
+    char *pcLine,
+    char *pc,
+    size_t errorlen,
+    const char *format,
+    ...)
+{
+    va_list argptr;
+
+    va_start(argptr, format);
+    Fatalv(filename, nLine, pcLine, pc, errorlen, format, argptr);
+    va_end(argptr);
+}
+
 int
 ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
 {
@@ -743,20 +811,38 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
 
         /* Now we should get either an ordinal or @ */
         if (*pc == '@')
+        {
             exp.nOrdinal = -1;
-        else
+        }
+        else if ((*pc >= '0') && (*pc <= '9'))
         {
-            exp.nOrdinal = atol(pc);
+            char* end;
+            long int number = strtol(pc, &end, 10);
+            if ((*end != ' ') && (*end != '\t'))
+            {
+                Fatal(pszSourceFileName, nLine, pcLine, end, 0, "Unexpected character(s) after ordinal");
+            }
+
+            if ((number < 0) || (number > 0xFFFE))
+            {
+                Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid value for ordinal");
+            }
+
+            exp.nOrdinal = number;
+
             /* The import lib should contain the ordinal only if -ordinal was specified */
             if (!gbImportLib)
                 exp.uFlags |= FL_ORDINAL;
         }
+        else
+        {
+            Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Expected '@' or ordinal");
+        }
 
         /* Go to next token (type) */
         if (!(pc = NextToken(pc)))
         {
-            fprintf(stderr, "%s line %d: error: unexpected end of line\n", pszSourceFileName, nLine);
-            return -10;
+            Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
         }
 
         //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
@@ -789,16 +875,13 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
         }
         else
         {
-            fprintf(stderr, "%s line %d: error: expected callconv, got '%.*s' %d\n",
-                    pszSourceFileName, nLine, TokenLength(pc), pc, *pc);
-            return -11;
+            Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid calling convention");
         }
 
         /* Go to next token (options or name) */
         if (!(pc = NextToken(pc)))
         {
-            fprintf(stderr, "fail2\n");
-            return -12;
+            Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
         }
 
         /* Handle options */
@@ -832,6 +915,8 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
             }
             else if (CompareToken(pc, "-version="))
             {
+                char * pcVersionStart = pc + 9;
+
                 /* Default to not included */
                 version_included = 0;
                 pc += 8;
@@ -865,8 +950,12 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
                     /* Check for degenerate range */
                     if (version > endversion)
                     {
-                        fprintf(stderr, "%s line %d: error: invalid version rangen\n", pszSourceFileName, nLine);
-                        return -1;
+                        Fatal(pszSourceFileName,
+                              nLine,
+                              pcLine,
+                              pcVersionStart,
+                              pc - pcVersionStart,
+                              "Invalid version range");
                     }
 
                     /* Now compare the range with our version */
@@ -915,8 +1004,12 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
             }
             else
             {
-                fprintf(stderr, "info: ignored option: '%.*s'\n",
-                        TokenLength(pc), pc);
+                fprintf(stdout,
+                        "INFO: %s line %d: Ignored option: '%.*s'\n",
+                        pszSourceFileName,
+                        nLine,
+                        TokenLength(pc),
+                        pc);
             }
 
             /* Go to next token */
@@ -931,7 +1024,7 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
         /* Get name */
         exp.strName.buf = pc;
         exp.strName.len = TokenLength(pc);
-        DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf);
+        //DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf);
 
         /* Check for autoname */
         if ((exp.strName.len == 1) && (exp.strName.buf[0] == '@'))
@@ -950,15 +1043,13 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
             /* Go to next token */
             if (!(pc = NextToken(pc)))
             {
-                fprintf(stderr, "%s line %d: error: expected token\n", pszSourceFileName, nLine);
-                return -13;
+                Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
             }
 
             /* Verify syntax */
             if (*pc++ != '(')
             {
-                fprintf(stderr, "%s line %d: error: expected '('\n", pszSourceFileName, nLine);
-                return -14;
+                Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected '('");
             }
 
             /* Skip whitespaces */
@@ -1008,23 +1099,23 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
                     exp.anArgs[exp.nArgCount] = ARG_FLOAT;
                 }
                 else
-                    fprintf(stderr, "%s line %d: error: expected type, got: %.10s\n", pszSourceFileName, nLine, pc);
+                {
+                    Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Unrecognized type");
+                }
 
                 exp.nArgCount++;
 
                 /* Go to next parameter */
                 if (!(pc = NextToken(pc)))
                 {
-                    fprintf(stderr, "fail5\n");
-                    return -15;
+                    Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
                 }
             }
 
             /* Check syntax */
             if (*pc++ != ')')
             {
-                fprintf(stderr, "%s line %d: error: expected ')'\n", pszSourceFileName, nLine);
-                return -16;
+                Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected ')'");
             }
         }
 
@@ -1049,8 +1140,7 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
                     exp.strName.len = (int)(p - pc);
                     if (exp.strName.len < 1)
                     {
-                        fprintf(stderr, "%s line %d: error: unexpected @ found\n", pszSourceFileName, nLine);
-                        return -1;
+                        Fatal(pszSourceFileName, nLine, pcLine, p, 1, "Unexpected @");
                     }
                     exp.nStackBytes = atoi(p + 1);
                     exp.nArgCount =  exp.nStackBytes / 4;
@@ -1072,8 +1162,7 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
             /* Check syntax (end of line) */
             if (NextToken(pc))
             {
-                 fprintf(stderr, "%s line %d: error: additional tokens after ')'\n", pszSourceFileName, nLine);
-                 return -17;
+                Fatal(pszSourceFileName, nLine, pcLine, NextToken(pc), 0, "Excess token(s) at end of definition");
             }
 
             /* Don't relay-trace forwarded functions */
@@ -1088,8 +1177,7 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
         /* Check for no-name without ordinal */
         if ((exp.uFlags & FL_ORDINAL) && (exp.nOrdinal == -1))
         {
-            fprintf(stderr, "%s line %d: error: ordinal export without ordinal!\n", pszSourceFileName, nLine);
-            return -1;
+            Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Ordinal export without ordinal");
         }
 
         /*
@@ -1113,12 +1201,12 @@ ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
                         /* The current export is an OLE export: display the corresponding warning */
                         if (bIsNotPrivate)
                         {
-                            fprintf(stderr, "%s line %d: warning: exported symbol '%.*s' should be PRIVATE\n",
+                            fprintf(stderr, "WARNING: %s line %d: Exported symbol '%.*s' should be PRIVATE\n",
                                     pszSourceFileName, nLine, exp.strName.len, exp.strName.buf);
                         }
                         if (bHasOrdinal)
                         {
-                            fprintf(stderr, "%s line %d: warning: exported symbol '%.*s' should not be assigned an ordinal\n",
+                            fprintf(stderr, "WARNING: %s line %d: exported symbol '%.*s' should not be assigned an ordinal\n",
                                     pszSourceFileName, nLine, exp.strName.len, exp.strName.buf);
                         }
                         break;