Add support for #pragma foo(bar)

Report unsupported/unknown preprocessor directives.
Report line number of error rather than character offset.
diff --git a/include/acc/acc.h b/include/acc/acc.h
index 054d6a0..e25fde0 100644
--- a/include/acc/acc.h
+++ b/include/acc/acc.h
@@ -69,6 +69,9 @@
 void accGetScriptLabel(ACCscript* script, const ACCchar * name,
                        ACCvoid** address);
 
+void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
+                   ACCsizei maxStringCount, ACCchar** strings);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 733f188..096500d 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1039,16 +1039,35 @@
 
     class InputStream {
     public:
+        int getChar() {
+            if (bumpLine) {
+                line++;
+                bumpLine = false;
+            }
+            int ch = get();
+            if (ch == '\n') {
+                bumpLine = true;
+            }
+            return ch;
+        }
+        int getLine() {
+            return line;
+        }
+    protected:
+        InputStream() :
+            line(1), bumpLine(false) {
+        }
+    private:
         virtual int get() = 0;
-        virtual long tell() = 0;
+        int line;
+        bool bumpLine;
     };
 
     class FileInputStream : public InputStream {
     public:
         FileInputStream(FILE* in) : f(in) {}
-        virtual int get() { return fgetc(f); }
-        virtual long tell() { return ftell(f); }
     private:
+        virtual int get() { return fgetc(f); }
         FILE* f;
     };
 
@@ -1057,14 +1076,12 @@
         TextInputStream(const char* text, size_t textLength)
             : pText(text), mTextLength(textLength), mPosition(0) {
         }
+
+    private:
         virtual int get() {
             return mPosition < mTextLength ? pText[mPosition++] : EOF;
         }
-        virtual long tell() {
-            return mPosition;
-        }
 
-    private:
         const char* pText;
         size_t mTextLength;
         size_t mPosition;
@@ -1091,14 +1108,83 @@
     CodeBuf codeBuf;
     CodeGenerator* pGen;
 
-    static const int ERROR_BUF_SIZE = 512;
-    char mErrorBuf[ERROR_BUF_SIZE];
+    class String {
+    public:
+        String() {
+            mpBase = 0;
+            mUsed = 0;
+            mSize = 0;
+        }
+
+        ~String() {
+            if (mpBase) {
+                free(mpBase);
+            }
+        }
+
+        char* getUnwrapped() {
+            return mpBase;
+        }
+
+        void appendCStr(const char* s) {
+            int n = strlen(s);
+            memcpy(ensure(n), s, n + 1);
+        }
+
+        void append(char c) {
+            * ensure(1) = c;
+        }
+
+        void printf(const char* fmt,...) {
+            va_list ap;
+            va_start(ap, fmt);
+            vprintf(fmt, ap);
+            va_end(ap);
+        }
+
+        void vprintf(const char* fmt, va_list ap) {
+            char* temp;
+            int numChars = vasprintf(&temp, fmt, ap);
+            memcpy(ensure(numChars), temp, numChars+1);
+            free(temp);
+        }
+
+        size_t len() {
+            return mUsed;
+        }
+
+    private:
+        char* ensure(int n) {
+            size_t newUsed = mUsed + n;
+            if (newUsed > mSize) {
+                size_t newSize = mSize * 2 + 10;
+                if (newSize < newUsed) {
+                    newSize = newUsed;
+                }
+                mpBase = (char*) realloc(mpBase, newSize + 1);
+                mSize = newSize;
+            }
+            mpBase[newUsed] = '\0';
+            char* result = mpBase + mUsed;
+            mUsed = newUsed;
+            return result;
+        }
+
+        char* mpBase;
+        size_t mUsed;
+        size_t mSize;
+    };
+
+    String mErrorBuf;
+
     jmp_buf mErrorRecoveryJumpBuf;
 
+    String mPragmas;
+    int mPragmaStringCount;
+
     static const int ALLOC_SIZE = 99999;
 
-    /* depends on the init string */
-    static const int TOK_STR_SIZE = 48;
+    // Indentifiers start at 0x100 and increase by # (chars + 1) * 8
     static const int TOK_IDENT = 0x100;
     static const int TOK_INT = 0x100;
     static const int TOK_IF = 0x120;
@@ -1107,8 +1193,9 @@
     static const int TOK_BREAK = 0x190;
     static const int TOK_RETURN = 0x1c0;
     static const int TOK_FOR = 0x1f8;
-    static const int TOK_DEFINE = 0x218;
-    static const int TOK_MAIN = 0x250;
+    static const int TOK_PRAGMA = 0x218;
+    static const int TOK_DEFINE = TOK_PRAGMA + (7*8);
+    static const int TOK_MAIN = TOK_DEFINE + (7*8);
 
     static const int TOK_DUMMY = 1;
     static const int TOK_NUM = 2;
@@ -1168,7 +1255,7 @@
                 ch = dch;
             }
         } else
-            ch = file->get();
+            ch = file->getChar();
         /*    printf("ch=%c 0x%x\n", ch, ch); */
     }
 
@@ -1197,14 +1284,18 @@
                     pdef(TAG_TOK); /* fill last ident tag */
                     *(int *) tok = SYM_DEFINE;
                     *(char* *) (tok + 4) = dstk; /* define stack */
-                }
-                /* well we always save the values ! */
-                while (ch != '\n') {
+                    while (ch != '\n') {
+                        pdef(ch);
+                        inp();
+                    }
                     pdef(ch);
-                    inp();
+                    pdef(TAG_MACRO);
+                } else if (tok == TOK_PRAGMA) {
+                    doPragma();
+                } else {
+                    error("Unsupported preprocessor directive \"%s\"", last_id);
                 }
-                pdef(ch);
-                pdef(TAG_MACRO);
+
             }
             inp();
         }
@@ -1321,23 +1412,54 @@
 #endif
     }
 
+    void doPragma() {
+        // # pragma name(val)
+        int state = 0;
+        while(ch != EOF && ch != '\n' && state < 10) {
+            switch(state) {
+                case 0:
+                    if (isspace(ch)) {
+                        inp();
+                    } else {
+                        state++;
+                    }
+                    break;
+                case 1:
+                    if (isalnum(ch)) {
+                        mPragmas.append(ch);
+                        inp();
+                    } else if (ch == '(') {
+                        mPragmas.append(0);
+                        inp();
+                        state++;
+                    } else {
+                        state = 11;
+                    }
+                    break;
+                case 2:
+                    if (isalnum(ch)) {
+                        mPragmas.append(ch);
+                        inp();
+                    } else if (ch == ')') {
+                        mPragmas.append(0);
+                        inp();
+                        state = 10;
+                    } else {
+                        state = 11;
+                    }
+                    break;
+            }
+        }
+        if(state != 10) {
+            error("Unexpected pragma syntax");
+        }
+        mPragmaStringCount += 2;
+    }
 
     virtual void verror(const char* fmt, va_list ap) {
-        char* pBase = mErrorBuf;
-        int bytesLeft = sizeof(mErrorBuf);
-        int bytesAdded = snprintf(pBase, bytesLeft, "%ld: ", file->tell());
-        bytesLeft -= bytesAdded;
-        pBase += bytesAdded;
-        if (bytesLeft > 0) {
-            bytesAdded = vsnprintf(pBase, bytesLeft, fmt, ap);
-            bytesLeft -= bytesAdded;
-            pBase += bytesAdded;
-        }
-        if (bytesLeft > 0) {
-            bytesAdded = snprintf(pBase, bytesLeft, "\n");
-            bytesLeft -= bytesAdded;
-            pBase += bytesAdded;
-        }
+        mErrorBuf.printf("%ld: ", file->getLine());
+        mErrorBuf.vprintf(fmt, ap);
+        mErrorBuf.printf("\n");
         longjmp(mErrorRecoveryJumpBuf, 1);
     }
 
@@ -1680,7 +1802,7 @@
         pGlobalBase = 0;
         pVarsBase = 0;
         pGen = 0;
-        mErrorBuf[0] = 0;
+        mPragmaStringCount = 0;
     }
 
     void setArchitecture(const char* architecture) {
@@ -1745,9 +1867,10 @@
             pGen->init(&codeBuf);
             file = new TextInputStream(text, textLength);
             sym_stk = (char*) calloc(1, ALLOC_SIZE);
-            dstk = strcpy(sym_stk,
-                    " int if else while break return for define main ")
-                    + TOK_STR_SIZE;
+            static const char* predefinedSymbols =
+                " int if else while break return for pragma define main ";
+            dstk = strcpy(sym_stk, predefinedSymbols)
+                    + strlen(predefinedSymbols);
             pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
             glo = pGlobalBase;
             pVarsBase = (char*) calloc(1, ALLOC_SIZE);
@@ -1810,8 +1933,26 @@
         return NULL;
     }
 
+    void getPragmas(ACCsizei* actualStringCount,
+                    ACCsizei maxStringCount, ACCchar** strings) {
+        int stringCount = mPragmaStringCount;
+        if (actualStringCount) {
+            *actualStringCount = stringCount;
+        }
+        if (stringCount > maxStringCount) {
+            stringCount = maxStringCount;
+        }
+        if (strings) {
+            char* pPragmas = mPragmas.getUnwrapped();
+            while (stringCount-- > 0) {
+                *strings++ = pPragmas;
+                pPragmas += strlen(pPragmas) + 1;
+            }
+        }
+    }
+
     char* getErrorMessage() {
-        return mErrorBuf;
+        return mErrorBuf.getUnwrapped();
     }
 
 };
@@ -1988,5 +2129,12 @@
     }
 }
 
+extern "C"
+void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
+                   ACCsizei maxStringCount, ACCchar** strings){
+    script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
+}
+
+
 } // namespace acc
 
diff --git a/libacc/tests/data/otcc-noinclude.c b/libacc/tests/data/otcc-noinclude.c
new file mode 100644
index 0000000..530f9e2
--- /dev/null
+++ b/libacc/tests/data/otcc-noinclude.c
@@ -0,0 +1,446 @@
+// #include <stdio.h>
+#define k *(int*)
+#define a if(
+#define c ad()
+#define i else
+#define p while(
+#define x *(char*)
+#define b ==
+#define V =calloc(1,99999)
+#define f ()
+#define J return
+#define l ae(
+#define n e)
+#define u d!=
+#define F int 
+#define y (j)
+#define r m=
+#define t +4
+F d,z,C,h,P,K,ac,q,G,v,Q,R,D,L,W,M;
+E(n{
+x D++=e;
+}
+o f{
+a L){
+h=x L++;
+a h b 2){
+L=0;
+h=W;
+}
+}
+i h=fgetc(Q);
+}
+X f{
+J isalnum(h)|h b 95;
+}
+Y f{
+a h b 92){
+o f;
+a h b 110)h=10;
+}
+}
+c{
+F e,j,m;
+p isspace(h)|h b 35){
+a h b 35){
+o f;
+c;
+a d b 536){
+c;
+E(32);
+k d=1;
+k(d t)=D;
+}
+p h!=10){
+E(h);
+o f;
+}
+E(h);
+E(2);
+}
+o f;
+}
+C=0;
+d=h;
+a X f){
+E(32);
+M=D;
+p X f){
+E(h);
+o f;
+}
+a isdigit(d)){
+z=strtol(M,0,0);
+d=2;
+}
+i{
+x D=32;
+d=strstr(R,M-1)-R;
+x D=0;
+d=d*8+256;
+a d>536){
+d=P+d;
+a k d b 1){
+L=k(d t);
+W=h;
+o f;
+c;
+}
+}
+}
+}
+i{
+o f;
+a d b 39){
+d=2;
+Y f;
+z=h;
+o f;
+o f;
+}
+i a d b 47&h b 42){
+o f;
+p h){
+p h!=42)o f;
+o f;
+a h b 47)h=0;
+}
+o f;
+c;
+}
+i{
+e="++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<<Z/03e>>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b";
+p j=x e++){
+r x e++;
+z=0;
+p(C=x e++-98)<0)z=z*64+C+64;
+a j b d&(m b h|m b 64)){
+a m b h){
+o f;
+d=1;
+}
+break;
+}
+}
+}
+}
+}
+l g){
+p g&&g!=-1){
+x q++=g;
+g=g>>8;
+}
+}
+A(n{
+F g;
+p n{
+g=k e;
+k e=q-e-4;
+e=g;
+}
+}
+s(g,n{
+l g);
+k q=e;
+e=q;
+q=q t;
+J e;
+}
+H(n{
+s(184,n;
+}
+B(n{
+J s(233,n;
+}
+S(j,n{
+l 1032325);
+J s(132+j,n;
+}
+Z(n{
+l 49465);
+H(0);
+l 15);
+l e+144);
+l 192);
+}
+N(j,n{
+l j+131);
+s((e<512)<<7|5,n;
+}
+T y{
+F g,e,m,aa;
+g=1;
+a d b 34){
+H(v);
+p h!=34){
+Y f;
+x v++=h;
+o f;
+}
+x v=0;
+v=v t&-4;
+o f;
+c;
+}
+i{
+aa=C;
+r z;
+e=d;
+c;
+a e b 2){
+H(m);
+}
+i a aa b 2){
+T(0);
+s(185,0);
+a e b 33)Z(m);
+i l m);
+}
+i a e b 40){
+w f;
+c;
+}
+i a e b 42){
+c;
+e=d;
+c;
+c;
+a d b 42){
+c;
+c;
+c;
+c;
+e=0;
+}
+c;
+T(0);
+a d b 61){
+c;
+l 80);
+w f;
+l 89);
+l 392+(e b 256));
+}
+i a n{
+a e b 256)l 139);
+i l 48655);
+q++;
+}
+}
+i a e b 38){
+N(10,k d);
+c;
+}
+i{
+g=k e;
+a!g)g=dlsym(0,M);
+a d b 61&j){
+c;
+w f;
+N(6,g);
+}
+i a u 40){
+N(8,g);
+a C b 11){
+N(0,g);
+l z);
+c;
+}
+}
+}
+}
+a d b 40){
+a g b 1)l 80);
+r s(60545,0);
+c;
+j=0;
+p u 41){
+w f;
+s(2393225,j);
+a d b 44)c;
+j=j t;
+}
+k r j;
+c;
+a!g){
+e=e t;
+k e=s(232,k n;
+}
+i a g b 1){
+s(2397439,j);
+j=j t;
+}
+i{
+s(232,g-q-5);
+}
+a j)s(50305,j);
+}
+}
+O y{
+F e,g,m;
+a j--b 1)T(1);
+i{
+O y;
+r 0;
+p j b C){
+g=d;
+e=z;
+c;
+a j>8){
+r S(e,m);
+O y;
+}
+i{
+l 80);
+O y;
+l 89);
+a j b 4|j b 5){
+Z(n;
+}
+i{
+l n;
+a g b 37)l 146);
+}
+}
+}
+a m&&j>8){
+r S(e,m);
+H(e^1);
+B(5);
+A(m);
+H(n;
+}
+}
+}
+w f{
+O(11);
+}
+U f{
+w f;
+J S(0,0);
+}
+I y{
+F m,g,e;
+a d b 288){
+c;
+c;
+r U f;
+c;
+I y;
+a d b 312){
+c;
+g=B(0);
+A(m);
+I y;
+A(g);
+}
+i{
+A(m);
+}
+}
+i a d b 352|d b 504){
+e=d;
+c;
+c;
+a e b 352){
+g=q;
+r U f;
+}
+i{
+a u 59)w f;
+c;
+g=q;
+r 0;
+a u 59)r U f;
+c;
+a u 41){
+e=B(0);
+w f;
+B(g-q-5);
+A(n;
+g=e t;
+}
+}
+c;
+I(&m);
+B(g-q-5);
+A(m);
+}
+i a d b 123){
+c;
+ab(1);
+p u 125)I y;
+c;
+}
+i{
+a d b 448){
+c;
+a u 59)w f;
+K=B(K);
+}
+i a d b 400){
+c;
+k j=B(k j);
+}
+i a u 59)w f;
+c;
+}
+}
+ab y{
+F m;
+p d b 256|u-1&!j){
+a d b 256){
+c;
+p u 59){
+a j){
+G=G t;
+k d=-G;
+}
+i{
+k d=v;
+v=v t;
+}
+c;
+a d b 44)c;
+}
+c;
+}
+i{
+A(k(d t));
+k d=q;
+c;
+c;
+r 8;
+p u 41){
+k d=m;
+r m t;
+c;
+a d b 44)c;
+}
+c;
+K=G=0;
+l 15042901);
+r s(60545,0);
+I(0);
+A(K);
+l 50121);
+k r G;
+}
+}
+}
+main(g,n{
+Q=stdin;
+a g-->1){
+e=e t;
+Q=fopen(k e,"r");
+}
+D=strcpy(R V," int if else while break return for define main ")+48;
+v V;
+q=ac V;
+P V;
+o f;
+c;
+ab(0);
+J(*(int(*)f)k(P+592))(g,n;
+}
+
diff --git a/libacc/tests/data/returnval.c b/libacc/tests/data/returnval.c
index 3142fe2..1b9dd81 100644
--- a/libacc/tests/data/returnval.c
+++ b/libacc/tests/data/returnval.c
@@ -1,3 +1,7 @@
+#pragma foo3(bar) //sdfsfd
+#pragma a(b)
+
 main() {
   return 42;
-}
\ No newline at end of file
+}
+
diff --git a/libacc/tests/main.cpp b/libacc/tests/main.cpp
index e65103e..6b39f57 100644
--- a/libacc/tests/main.cpp
+++ b/libacc/tests/main.cpp
@@ -86,10 +86,23 @@
     if (result != 0) {
         char buf[1024];
         accGetScriptInfoLog(script, sizeof(buf), NULL, buf);
-        fprintf(stderr, "%ss", buf);
+        fprintf(stderr, "%s", buf);
         goto exit;
     }
 
+    {
+        ACCsizei numPragmaStrings;
+        accGetPragmas(script, &numPragmaStrings, 0, NULL);
+        if (numPragmaStrings) {
+            char** strings = new char*[numPragmaStrings];
+            accGetPragmas(script, NULL, numPragmaStrings, strings);
+            for(ACCsizei i = 0; i < numPragmaStrings; i += 2) {
+                fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]);
+            }
+            delete[] strings;
+        }
+    }
+
     accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer);
 
     result = accGetError(script);
diff --git a/libacc/tests/testlocal b/libacc/tests/testlocal
index a76322b..547aed5 100755
--- a/libacc/tests/testlocal
+++ b/libacc/tests/testlocal
@@ -8,8 +8,8 @@
 
   if [ "$(uname)" = "Linux" ]; then
     if [ "$(uname -m)" = "i686" ]; then
-      echo "Linux i686. Testing otcc.c"
-      ./test-acc data/otcc.c data/otcc.c data/returnval.c
+      echo "Linux i686. Testing otcc-noinclude.c"
+      ./test-acc data/otcc-noinclude.c data/otcc.c data/returnval.c
     fi
   fi
 fi