]> git.sur5r.net Git - cc65/commitdiff
Added assembler include function for _scanf
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 27 Nov 2004 14:45:49 +0000 (14:45 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 27 Nov 2004 14:45:49 +0000 (14:45 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@3304 b7a2c559-68d2-44c3-8de9-860c34a00d81

libsrc/common/_scanf.c
libsrc/common/_scanf.h
libsrc/common/_scanf.inc [new file with mode: 0644]

index 53d65694e03ade1fecff15378457ba8c10530230..367c09af7be783c378c1c6b4ebbe24b8d0fabdf6 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <stddef.h>
 #include <string.h>
 #include <setjmp.h>
 #include <ctype.h>
 
 
 
-static struct scanfdata*  D          /* Copy of function argument */
-static va_list           ap;           /* Copy of function argument */
+static struct scanfdata*  D_;          /* Copy of function argument */
+static va_list                   ap;           /* Copy of function argument */
 static jmp_buf                   JumpBuf;      /* Label that is used in case of EOF */
+static unsigned           CharCount;    /* Characters read so far */
 static int                C;                   /* Character from input */
 static unsigned                  Width;        /* Maximum field width */
 static long                      IntVal;       /* Converted int value */
@@ -57,6 +59,15 @@ static const unsigned char Bits[8] = {
     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
 };
 
+/* We need C to be 16 bits since we cannot check for EOF otherwise.
+ * Unfortunately, this causes the code to be quite larger, even if for most
+ * purposes, checking the low byte would be enough, since if C is EOF, the
+ * low byte will not match any useful character anyway (at least for the
+ * supported platforms - I know that this is not portable). So the following
+ * macro is used to access just the low byte of C.
+ */
+#define CHAR(c)         (*((unsigned char*)&(c)))
+
 
 
 /*****************************************************************************/
@@ -124,13 +135,57 @@ static void InvertCharSet (void)
 
 
 
+static void __fastcall__ Error (unsigned char Code)
+/* Does a longjmp using the given code */
+{
+    longjmp (JumpBuf, Code);
+}
+
+
+
 static void ReadChar (void)
 /* Get an input character, count characters */
 {
-    C = D->get (D->data);
-    if (C != EOF) {
-        ++D->ccount;
-    }
+    /* Move D to ptr1 */
+    asm ("lda %v", D_);
+    asm ("ldx %v+1", D_);
+    asm ("sta ptr1");
+    asm ("stx ptr1+1");
+
+    /* Copy the get vector to jmpvec */
+    asm ("ldy #%b", offsetof (struct scanfdata, get));
+    asm ("lda (ptr1),y");
+    asm ("sta jmpvec+1");
+    asm ("iny");
+    asm ("lda (ptr1),y");
+    asm ("sta jmpvec+2");
+
+    /* Load D->data into __AX__ */
+    asm ("ldy #%b", offsetof (struct scanfdata, data)+1);
+    asm ("lda (ptr1),y");
+    asm ("tax");
+    asm ("dey");
+    asm ("lda (ptr1),y");
+
+    /* Call the get routine */
+    asm ("jsr jmpvec");
+
+    /* Assign the result to C */
+    asm ("sta %v", C);
+    asm ("stx %v+1", C);
+
+    /* If C is not EOF, bump the character counter. */
+    asm ("inx");
+    asm ("bne %g", Done);
+    asm ("cmp #$FF");
+    asm ("bne %g", Done);
+
+    /* Must bump CharCount. */
+    asm ("inc %v", CharCount);
+    asm ("bne %g", Done);
+    asm ("inc %v+1", CharCount);
+
+Done:
 }
 
 
@@ -140,7 +195,7 @@ static void ReadCharWithCheck (void)
 {
     ReadChar ();
     if (C == EOF) {
-       longjmp (JumpBuf, RC_EOF);
+       Error (RC_EOF);
     }
 }
 
@@ -161,17 +216,27 @@ static void ReadSign (void)
  * positive, store 0 otherwise.
  */
 {
-    switch (C) {
-       case '-':
-                   ReadChar ();
-           Positive = 0;
-            break;
-       case '+':
-           ReadChar ();
-           /* FALLTHROUGH */
-       default:
-           Positive = 1;
-    }
+    /* We can ignore the high byte of C here, since if it is EOF, the lower
+     * byte won't match anyway.
+     */
+    asm ("lda %v", C);
+    asm ("cmp #'-'");
+    asm ("bne %g", NotNeg);
+
+    /* Negative value */
+    asm ("jsr %v", ReadChar);
+    asm ("lda #$00");           /* Flag as negative */
+    asm ("beq %g", Store);
+
+    /* Positive value */
+NotNeg:
+    asm ("cmp #'+'");
+    asm ("bne %g", Pos);
+    asm ("jsr %v", ReadChar);   /* Skip the + sign */
+Pos:
+    asm ("lda #$01");           /* Flag as positive */
+Store:
+    asm ("sta %v", Positive);
 }
 
 
@@ -210,10 +275,10 @@ static void AssignInt (void)
         asm ("ldy %v", IntBytes);
 
         /* Assign the integer value */
-        asm ("L1: lda %v,y", IntVal);
+Loop:   asm ("lda %v,y", IntVal);
         asm ("sta (ptr1),y");
         asm ("dey");
-        asm ("bpl L1");
+        asm ("bpl %g", Loop);
 
     }
 }
@@ -238,7 +303,7 @@ static unsigned char ReadInt (unsigned char Base)
 
     /* If we didn't convert anything, it's an error */
     if (CharCount == 0) {
-       longjmp (JumpBuf, RC_NOCONV);
+       Error (RC_NOCONV);
     }
 
     /* Return the number of characters converted */
@@ -247,7 +312,7 @@ static unsigned char ReadInt (unsigned char Base)
 
 
 
-static void ScanInt (unsigned char Base)
+static void __fastcall__ ScanInt (unsigned char Base)
 /* Scan an integer including white space, sign and optional base spec,
  * and store it into IntVal.
  */
@@ -260,9 +325,9 @@ static void ScanInt (unsigned char Base)
 
     /* If Base is unknown (zero), figure it out */
     if (Base == 0) {
-        if (C == '0') {
+        if (CHAR (C) == '0') {
             ReadChar ();
-            switch (C) {
+            switch (CHAR (C)) {
                 case 'x':
                 case 'X':
                     Base = 16;
@@ -293,14 +358,15 @@ static void ScanInt (unsigned char Base)
 
 
 
-int _scanf (struct scanfdata* D_, register const char* format, va_list ap_)
+int __fastcall__ _scanf (register struct scanfdata* D,
+                         register const char* format, va_list ap_)
 /* This is the routine used to do the actual work. It is called from several
  * types of wrappers to implement the actual ISO xxscanf functions.
  */
 {
-    char         F;            /* Character from format string */
+    register char F;                   /* Character from format string */
     unsigned char Result;      /* setjmp result */
-    char*        S;
+    char*        S;
     unsigned char HaveWidth;   /* True if a width was given */
     char          Start;        /* Start of range */
 
@@ -308,12 +374,12 @@ int _scanf (struct scanfdata* D_, register const char* format, va_list ap_)
      * nice, but on a 6502 platform it gives better code, since the values
      * do not have to be passed as parameters.
      */
-    D  = D_;
+    D_         = D;
     ap = ap_;
 
     /* Initialize variables */
     Conversions = 0;
-    D->ccount   = 0;
+    CharCount   = 0;
 
     /* Set up the jump label. The get() routine will use this label when EOF
      * is reached.
@@ -429,7 +495,7 @@ Again:
 
                    case 'i':
                        /* Optionally signed integer with a base */
-                       ScanInt (0);
+                       ScanInt (0);
                        break;
 
                    case 'o':
@@ -448,13 +514,13 @@ Again:
                    case 'f':
                    case 'g':
                        /* Optionally signed float */
-                       longjmp (JumpBuf, RC_NOCONV);
+                       Error (RC_NOCONV);
                        break;
 
                    case 's':
                        /* Whitespace terminated string */
                        SkipWhite ();
-                       if (!NoAssign) {
+                       if (!NoAssign) {
                            S = va_arg (ap, char*);
                        }
                                while (!isspace (C) && Width--) {
@@ -465,34 +531,34 @@ Again:
                        }
                        /* Terminate the string just read */
                        if (!NoAssign) {
-                           *S = '\0';
-                       }
+                           *S = '\0';
+                       }
                         ++Conversions;
-                       break;
+                       break;
 
                    case 'c':
-                       /* Fixed length string, NOT zero terminated */
-                       if (!HaveWidth) {
-                           /* No width given, default is 1 */
-                           Width = 1;
-                       }
-                       if (!NoAssign) {
-                           S = va_arg (ap, char*);
+                       /* Fixed length string, NOT zero terminated */
+                       if (!HaveWidth) {
+                           /* No width given, default is 1 */
+                           Width = 1;
+                       }
+                       if (!NoAssign) {
+                           S = va_arg (ap, char*);
                             while (Width--) {
                                 *S++ = C;
                                 ReadCharWithCheck ();
                             }
-                       } else {
+                       } else {
                             /* Just skip as many chars as given */
                             while (Width--) {
                                 ReadCharWithCheck ();
                             }
                         }
-                       ++Conversions;
+                       ++Conversions;
                        break;
 
                    case '[':
-                       /* String using characters from a set */
+                       /* String using characters from a set */
                         Invert = 0;
                         /* Clear the set */
                         memset (CharSet, 0, sizeof (CharSet));
@@ -563,16 +629,16 @@ Again:
                    case 'p':
                        /* Pointer, format is 0xABCD */
                        SkipWhite ();
-                       if (C != '0') {
-                            longjmp (JumpBuf, RC_NOCONV);
+                       if (CHAR (C) != '0') {
+                            Error (RC_NOCONV);
                         }
                        ReadChar ();
-                        if (C != 'x' && C != 'X') {
-                            longjmp (JumpBuf, RC_NOCONV);
+                        if (CHAR (C) != 'x' && CHAR (C) != 'X') {
+                            Error (RC_NOCONV);
                         }
                         ReadChar ();
                         if (ReadInt (16) != 4) { /* 4 chars expected */
-                            longjmp (JumpBuf, RC_NOCONV);
+                            Error (RC_NOCONV);
                         }
                        AssignInt ();
                         ++Conversions;
@@ -580,13 +646,13 @@ Again:
 
                    case 'n':
                        /* Store characters consumed so far */
-                       IntVal = D->ccount;
+                       IntVal = CharCount;
                        AssignInt ();
                        break;
 
                    default:
                        /* Invalid conversion */
-                       longjmp (JumpBuf, RC_NOCONV);
+                       Error (RC_NOCONV);
                        break;
 
                }
@@ -604,7 +670,7 @@ Again:
          * conversions, it is considered an error, otherwise the number
          * of conversions is returned (the default behaviour).
          */
-               if (C == EOF && D->ccount == 0) {
+               if (C == EOF && CharCount == 0) {
            /* Special case: error */
            Conversions = EOF;
        }
@@ -617,3 +683,4 @@ Again:
 
 
 
+
index e477c37daafba9266b0918477201baeea74cf957..0dbf0e01bdff4ea8f11ce3ea71eda78876cf7070 100644 (file)
@@ -21,13 +21,12 @@ typedef int __fastcall__ (*ungetfunc) (int c, void* data);
 
 
 /* Control structure passed to the low level worker function.
- * Beware: The low level functions will access the structure on the assembly
- * level, so check this when altering the structure.
+ * Beware: This structure is mirrored in the _scanf.inc assembler include
+ * file, so check this when altering the structure.                     
  */
 struct scanfdata {
     getfunc                get;        /* Pointer to input routine */
     ungetfunc       unget;      /* Pointer to pushback routine */
-    unsigned       ccount;     /* Number of chars read */
 
     /* Fields used outside of _scanf */
     void*           data;       /* Caller data */
@@ -36,7 +35,7 @@ struct scanfdata {
 
 
 /* Internal scanning routine */
-int _scanf (struct scanfdata* d, const char* format, va_list ap);
+int __fastcall__ _scanf (struct scanfdata* d, const char* format, va_list ap);
 
 
 
diff --git a/libsrc/common/_scanf.inc b/libsrc/common/_scanf.inc
new file mode 100644 (file)
index 0000000..48ae5b0
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 2004-11-27
+;
+
+;----------------------------------------------------------------------------
+; Structure passed to _scanf
+
+.struct SCANFDATA
+        GET     .addr
+        UNGET   .addr
+        DATA    .addr
+.endstruct
+
+;----------------------------------------------------------------------------
+; Global data
+
+.global _scanf
+
+
+
+