CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

sscanf() for CCS
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

sscanf() for CCS
PostPosted: Fri Aug 13, 2004 10:05 am     Reply with quote

Okay, here is a sscanf() function for you CCS guys. I sort of cheated how I handled the variable arguments but I will include a test program so you can see how to use it. Enjoy

sscanf.c
Code:

/*$F*************************************************************************
*
* Copyright (C)pa 2004 Mark Norton
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Functional
* Description:  Implementation of sscanf() function for the CCS compiler
*
*****************************************************************************/
#include <string.h>
#include <stdlib.h>

int8 sscanf(
  char  *buf,    /* pointer to the buffer that we are scanning */
  char  *fmt,    /* pointer to the format string */
  char  *pArgs)  /* pointer to array of arguments */
{

  int8        count = 0;
  char        *p;
  int1        size_long;
  char        *endptr;

  while (1)
  {
   /* Look to see if we are out of arguments */
   if ( !pArgs )
     return( count );

   /* Gobble up the fmt string */
    while (*buf == *fmt)
    {
      if ((*buf == 0) || (*fmt == 0))
        return (count);
      buf++;
      fmt++;
    }

    /* Check for the % */
    if (*fmt != '%')
      break;

    /* fmt should be '%' go to the next character */
    fmt++;

    /* get the size modifier */
    switch (*fmt)
    {
      case 'l':
      case 'L':
        fmt++;
        size_long = TRUE;
        break;
      default:
        size_long = FALSE;
        break;
    }

    /* fmt should point to our first conversion letter at this point */
    switch (*fmt)
    {
      case 'f':
      case 'F':
        /* Get a pointer to this argument */
        p = (float *)(*pArgs);

        /* convert to a number */
        *(float *)p = (float)strtod(buf, &endptr);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
      case 'd':
      case 'D':
        /* Get a pointer to this argument */
        p = (signed int8 *)(*pArgs);

        /* convert to a number */
        if ( size_long )
          *(signed int16 *)p = (signed int16)strtol(buf, &endptr, 10);
        else
          *(signed int8 *)p = (signed int8)strtol(buf, &endptr, 10);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
      case 'u':
      case 'U':
        /* Get a pointer to this argument */
        p = (int8 *)(*pArgs);

        /* convert to a number */
        if ( size_long )
          *(int16 *)p = (int16) strtoul(buf, &endptr, 10);
        else
          *(int8 *)p = (int8) strtoul(buf, &endptr, 10);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
      case 's':
        /* Get a pointer to this argument */
        p = (char *)(*pArgs);

        /* copy the chars */
        while (1)
        {
          if ((isspace(*buf)) || (!*buf))
          {
            *p = 0;
            break;
          }
          else
          {
            *p = *buf;
            p++;
            buf++;
          }
        }

        /* count this one */
        count++;
        break;
      case 'x':
      case 'X':
        /* Get a pointer to this argument */
        p = (int8 *)(*pArgs);

        /* convert to a number */
        if ( size_long )
          *(int16 *)p = (int16) strtoul(buf, &endptr, 16);
        else
          *(int8 *)p = (int8) strtoul(buf, &endptr, 16);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;

      /* unhandled format specifier */
      default:
        return (count);
    }
    /* Technically this is incorrect but since the size of all pointers
       are the same, who cares ;)

       point to the next argument
    */
    pArgs += sizeof(char *);
   
    /* Move to the next format char */
    fmt++;
  }

  return (count);
}
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

And a test file
PostPosted: Fri Aug 13, 2004 10:05 am     Reply with quote

And here is a test file
test.c
Code:

#include <18F452.h>
#device *=16

#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)  // Jumpers: 8 to 11, 7 to 12


#include <input.c>
#include "sscanf.c"

void main(void) {

  int i=0;
  char string[80];
  char fmt[40];
  float vfloat;
  int8 vint8;
  int16 vint16;
  char vstring[10];
  signed int8 vsint8;
  signed int16 vsint16;
  int8 vhex;
  int16 vhexlong;
  int8* arglist[9];

  while(TRUE)
  {
    strcpy(fmt, "sscanf test %f %u %lu %s %d %ld %x %lx\r\n");
    arglist[0] = &vfloat;
    arglist[1] = &vint8;
    arglist[2] = &vint16;
    arglist[3] = &vstring[0];
    arglist[4] = &vsint8;
    arglist[5] = &vsint16;
    arglist[6] = &vhex;
    arglist[7] = &vhexlong;
    /* It is a good idea to terminate the list but not necessary if the format is correct */
    arglist[8] = NULL;

    printf("\r\nType sscanf test f u lu s d ld x lx\r\n");
    get_string(string, sizeof(string));
    i = sscanf(string, fmt, arglist);
    if ( i != 8 )
    {
      printf("\r\nFailed - %u parameters read",i);
      continue;
    }
    else
    {
      printf("\r\nVar Float = %f", vfloat);
      printf("\r\nVar Int = %u", vint8);
      printf("\r\nVar Long = %lu", vint16);
      printf("\r\nVar String = %s", vstring);
      printf("\r\nVar Signed Int = %d", vsint8);
      printf("\r\nVar Signed Long = %ld", vsint16);
      printf("\r\nVar Hex = %x", vhex);
      printf("\r\nVar Hex Long = %lx", vhexlong);
    }

    strcpy(fmt, "%f\r\n");
    arglist[0] = &vfloat;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a float (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%u\r\n");
    arglist[0] = &vint8;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a int (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%lu\r\n");
    arglist[0] = &vint16;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a long (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%s\r\n");
    arglist[0] = &vstring[0];
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a string (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%d\r\n");
    arglist[0] = &vsint8;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a signed int (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%ld\r\n");
    arglist[0] = &vsint16;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a signed long (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%x\r\n");
    arglist[0] = &vhex;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a hex (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

    strcpy(fmt, "%lx\r\n");
    arglist[0] = &vhexlong;
    arglist[1] = NULL;

    while (1)
    {
      printf("\r\nType in a long hex (enter to skip)\r\n");
      get_string(string, sizeof(string));
      if ( !string[0] )
        break;

      i = sscanf(string, fmt, arglist);
      if ( i != 1 )
      {
        printf("\r\nFailed - %u parameters read",i);
        continue;
      }
      else
      {
        printf("\r\nVar Float = %f", vfloat);
        printf("\r\nVar Int = %u", vint8);
        printf("\r\nVar Long = %lu", vint16);
        printf("\r\nVar String = %s", vstring);
        printf("\r\nVar Signed Int = %d", vsint8);
        printf("\r\nVar Signed Long = %ld", vsint16);
        printf("\r\nVar Hex = %x", vhex);
        printf("\r\nVar Hex Long = %lx", vhexlong);
      }
    }

  }
}
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

I put her on a diet
PostPosted: Fri Aug 13, 2004 2:04 pm     Reply with quote

This code is smaller and allows you to disable the formats that you are not using
Code:

/*$F*************************************************************************
*
* Copyright (C)pa 2004 Mark Norton
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Functional
* Description:  Implementation of sscanf() function for the CCS compiler
*
*****************************************************************************/
#include <string.h>
#include <stdlib.h>

/* Uncomment any of these to reduce the code size
   Note that the HEX is a big hog
*/
// #define NO_FLOAT
// #define NO_INT
// #define NO_SIGNED_INT
// #define NO_STRING
// #define NO_HEX

/* *************************************************************************
  DESCRIPTION:  Converts string pointed to by s to an unsigned long (16 bit)
  RETURN: result of the conversion
  ALGORITHM:  none
  NOTES:  the next position in the string is returned in endptr
 *************************************************************************** */
long my_atoul(char *s, char *endptr, int base)
{
  signed long result;
  int index;
  char c;

  index = 0;
  result = 0;
  *endptr = s;

  if (( !s ) || ( !*s ))
    return ( 0 );

  c = *s;

  // increase index if positive sign is detected
  if (c == '+')
  {
    c = *(++s);
  }

  // The number is a decimal number
  if (base == 10)
  {
    while (c >= '0' && c <= '9')
    {
      result = 10*result + (c - '0');
      c = *(++s);
    }
  }
  else if (base == 16)    // The number is a hexa number
  {
    if (c == '0' && (*(s+1) == 'x' || *(s+1) == 'X'))
    {
      s += 2;
      c = *s;
    }

    c = toupper(c);
    while ( 1 )
    {
      if (c >= '0' && c <= '9')
        result = (result << 4) + (c - '0');
      else if (c >= 'A' && c <='F')
        result = (result << 4) + (c - 'A' + 10);
      else
        break;
      c = toupper(*(++s));
    }
  }
  *endptr = s;
  return(result);
}

/* *************************************************************************
  DESCRIPTION:  Converts string pointed to by s to a float
  RETURN: result of the conversion
  ALGORITHM:  none
  NOTES:  the next position in the string is returned in endptr
 *************************************************************************** */
float my_atof(char * s, char *endptr)
{
  float pow10 = 1.0;
  float result = 0.0;
  int sign = 0;
  char c;

  c = *s;

  if(c == '-')
  {
    sign = 1;
    c = *(++s);
  }
  else if(c == '+')
    c = *(++s);


  while((c >= '0' && c <= '9'))
  {
    result = 10*result + c - '0';
    c = *(++s);
  }

  if (c == '.')
  {
    c = *(++s);
    while((c >= '0' && c <= '9'))
    {
      pow10 = pow10*10;
      result += (c - '0')/pow10;
      c = *(++s);
    }
  }

   if (sign == 1)
     result = -1*result;

  *endptr = s;
  return(result);
}


/* *************************************************************************
  DESCRIPTION:  Implementation of scanf() using CCS C compiler
  RETURN: total number of arguments read
  ALGORITHM:  none
  NOTES:  none
 *************************************************************************** */
int8 sscanf(
  char  *buf,    /* pointer to the buffer that we are scanning */
  char  *fmt,    /* pointer to the format string */
  char  *pArgs)  /* pointer to array of arguments */
{

  int8        count = 0;
  char        *p;
  int1        size_long;
  int1        sign;
  char        *endptr;

  while (1)
  {
   /* Look to see if we are out of arguments */
   if ( !pArgs )
     return( count );

   /* Gobble up the fmt string */
    while (*buf == *fmt)
    {
      if ((*buf == 0) || (*fmt == 0))
        return (count);
      buf++;
      fmt++;
    }

    /* Check for the % */
    if (*fmt != '%')
      break;

    /* fmt should be '%' go to the next character */
    fmt++;

    /* get the size modifier */
    switch (*fmt)
    {
      case 'l':
      case 'L':
        fmt++;
        size_long = TRUE;
        break;
      default:
        size_long = FALSE;
        break;
    }

    /* fmt should point to our first conversion letter at this point */
    switch (*fmt)
    {
#ifndef NO_FLOAT
      case 'f':
      case 'F':
        /* Get a pointer to this argument */
        p = (float *)(*pArgs);

        /* convert to a number */
        *(float *)p = (float)my_atof(buf, &endptr);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_SIGNED_INT
      case 'd':
      case 'D':
        /* Get a pointer to this argument */
        p = (signed int8 *)(*pArgs);
        if (*buf == '-')
        {
          buf++;
          sign = TRUE;
        }
        else
          sign = FALSE;

        /* convert to a number */
        if ( size_long )
        {
          *(signed int16 *)p = (signed int16)my_atoul(buf, &endptr, 10);
          if (sign)
            *(signed int16 *)p = -(*(signed int16 *)p);
        }
        else
        {
          *(signed int8 *)p = (signed int8)my_atoul(buf, &endptr, 10);
          if (sign)
            *(signed int8 *)p = -(*(signed int8 *)p);
        }
        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_INT
      case 'u':
      case 'U':
        /* Get a pointer to this argument */
        p = (int8 *)(*pArgs);

        /* convert to a number */
        if ( size_long )
          *(int16 *)p = (int16) my_atoul(buf, &endptr, 10);
        else
          *(int8 *)p = (int8) my_atoul(buf, &endptr, 10);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_STRING
      case 's':
        /* Get a pointer to this argument */
        p = (char *)(*pArgs);

        /* copy the chars */
        while (1)
        {
          if ((isspace(*buf)) || (!*buf))
          {
            *p = 0;
            break;
          }
          else
          {
            *p = *buf;
            p++;
            buf++;
          }
        }

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_HEX
      case 'x':
      case 'X':
        /* Get a pointer to this argument */
        p = (int8 *)(*pArgs);

        /* convert to a number */
        if ( size_long )
          *(int16 *)p = (int16) my_atoul(buf, &endptr, 16);
        else
          *(int8 *)p = (int8) my_atoul(buf, &endptr, 16);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
      /* unhandled format specifier */
      default:
        return (count);
    }
    /* Technically this is incorrect but since the size of all pointers
       are the same, who cares ;)

       point to the next argument
    */
    pArgs += sizeof(char *);
   
    /* Move to the next format char */
    fmt++;
  }

  return (count);
}
maikelmeyers



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 1:03 pm     Reply with quote

You have to do a little change, when you want to use this routines with 16bit pointers

Code:

long my_atoul(char *s, int16 *endptr, int base)


otherwise *endptr = s; results in an unpridictable address
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Fri Jan 19, 2007 1:14 pm     Reply with quote

I don't think so. The 18F actually uses 16 bit pointers. Changing the pointer type will cause you problems when you increment the pointer. A pointer to a char will cause the value of the pointer to increment by 1 where as a pointer to a int16 will cause the value of the pointer to increment by 2!
maikelmeyers



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 4:44 pm     Reply with quote

It's not that I think only this was a problem. I've tried it, and this routine does not work without this little correction. It took a little time ;)

The increment is not the problem, it's this assignment in the long my_atoul() routine:

long my_atoul(char *s, char *endptr, int base)
*endptr = s;

endptr is used as a pointer to a pointer (16bit), but you defined that endptr is a pointer to char (8bit). Now, when you try to load the content to which endptr points, it will load only 8 bits, but s is a address (16bit), so the upper 8 bits of the address are not copied.

Sorry for my bad english, hope you understand now.

greets
maikelmeyers



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 4:49 pm     Reply with quote

And why don't you use the variable arguments list, like the original sscanf?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Sat Jan 20, 2007 2:51 pm     Reply with quote

maikelmeyers wrote:
And why don't you use the variable arguments list, like the original sscanf?
CCS didn't support them in 2004! Maybe they do now, but I am not sure
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Sat Jan 20, 2007 2:52 pm     Reply with quote

maikelmeyers wrote:
It's not that I think only this was a problem. I've tried it, and this routine does not work without this little correction. It took a little time ;)

The increment is not the problem, it's this assignment in the long my_atoul() routine:

long my_atoul(char *s, char *endptr, int base)
*endptr = s;

endptr is used as a pointer to a pointer (16bit), but you defined that endptr is a pointer to char (8bit). Now, when you try to load the content to which endptr points, it will load only 8 bits, but s is a address (16bit), so the upper 8 bits of the address are not copied.

Sorry for my bad english, hope you understand now.

greets

endptr should be a char** which is a pointer to a pointer.
maikelmeyers



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Mon Jan 22, 2007 6:51 am     Reply with quote

OK, now here is a version with variable arguments



Code:

/* *************************************************************************
  DESCRIPTION:  Implementation of scanf() using CCS C compiler
  RETURN: total number of arguments read
  ALGORITHM:  none
  NOTES:  none
 *************************************************************************** */
int8 sscanf(
  char  *buf,    /* pointer to the buffer that we are scanning */
  char  *fmt,    /* pointer to the format string */
         ...)      /* variable arguments */
{

  va_list      pArgs;
  int8        count = 0;
  char        *p;
  int1        size_long;
  int1        sign;
  char        *endptr;

  va_start (pArgs,0);

  while (TRUE)
  {


   /* Gobble up the fmt string */
    while (*buf == *fmt)
    {
      if ((*buf == 0) || (*fmt == 0))
        return (count);
    
      buf++;
      fmt++;
    }

    /* Check for the % */
    if (*fmt != '%')
      break;

    /* fmt should be '%' go to the next character */
    fmt++;

    /* get the size modifier */
    switch (*fmt)
    {
      case 'l':
      case 'L':
        fmt++;
        size_long = TRUE;
        break;
      default:
        size_long = FALSE;
        break;
    }

    /* fmt should point to our first conversion letter at this point */
    switch (*fmt)
    {
#ifndef NO_FLOAT
      case 'f':
      case 'F':

        /* convert to a number */
        *((float *)va_arg(pArgs,float*)) = my_atof(buf, &endptr);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );       
   
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_SIGNED_INT
      case 'd':
      case 'D':
        /* Get a pointer to this argument */
        p = va_arg(pArgs,signed int16*);

        if (*buf == '-')
        {
          buf++;
          sign = TRUE;
        }
        else
          sign = FALSE;

        /* convert to a number */
        if ( size_long )
        {
          *(signed int16 *)p = (signed int16)my_atoul(buf, &endptr, 10);
          if (sign)
            *(signed int16 *)p = -(*(signed int16 *)p);
        }
        else
        {
          *(signed int8 *)p = (signed int8)my_atoul(buf, &endptr, 10);
          if (sign)
            *(signed int8 *)p = -(*(signed int8 *)p);
        }
        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
      
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_INT
      case 'u':
      case 'U':

        /* convert to a number */
        if ( size_long )
          *((int16*)va_arg(pArgs,int16*)) = (int16) my_atoul(buf, &endptr, 10);
        else
          *((int8 *)va_arg(pArgs,int8*))  = (int8) my_atoul(buf, &endptr, 10);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
      
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_STRING
      case 's':
        /* Get a pointer to this argument */
        p = (char *) va_arg(pArgs,char *);

        /* copy the chars */
        while (TRUE)
        {
          if ((isspace(*buf)) || (!*buf))
          {
            *p = 0;
            break;
          }
          else
          {
            *p = *buf;
            p++;
            buf++;
          }
        }

        /* count this one */
        count++;
        break;
#endif
#ifndef NO_HEX
      case 'x':
      case 'X':
       

        /* convert to a number */
        if ( size_long )
          *((int16*)va_arg(pArgs,int16*)) = (int16) my_atoul(buf, &endptr, 16);
        else
          *((int8 *)va_arg(pArgs,int8*))  = (int8) my_atoul(buf, &endptr, 16);

        /* Make sure that we succeeded */
        if ( buf == endptr )
          return ( count );
      
        buf = endptr;

        /* count this one */
        count++;
        break;
#endif
      /* unhandled format specifier */
      default:
        return (count);
    }

   
    /* Move to the next format char */
    fmt++;
  }
   
  return (count);
}
robinaspey



Joined: 01 Oct 2008
Posts: 4
Location: England (for time being)

View user's profile Send private message

sscanf code (Mark Norton)
PostPosted: Wed Oct 01, 2008 10:07 am     Reply with quote

I'm having some trouble with the versions of sscanf posted, here is the
code I was using to test the function (below):

The error I get is passing the pointer to the parameter buffer which
is passed to sscanf Message is: "Attempt to create a pointer to a constant"
which I cant get past ?!

Code:
#include    <18F452.h>
#device    ICD=TRUE *=16   // 16 bit pointers
#include    <stdio.h>
#include    <string.h>
#include   "sscanf_3.c"

#fuses      HS, WDT, BROWNOUT, NOPROTECT, NOPUT
#fill_rom            0xFF
#HEXCOMMENT   Version 0.1   // Add comment to HEX EEPROM file

#use       DELAY(CLOCK=20000000, RESTART_WDT)
#use       RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, RESTART_WDT, ERRORS, STREAM=ASTID)

typedef    unsigned    char    BOOL ;
typedef    unsigned    char     UINT8;      // 1 byte  0 to 255
typedef    unsigned    int16     UINT16;     // 2 bytes 0 to 65535
typedef    unsigned    int32     UINT32;     // 4 bytes 0 to 4294967295

int      main(void)
{
UINT8 counter   =   0     ;
UINT8 hours    =    5     ;
UINT8 minutes    =    0     ;
UINT8 seconds   =    0      ;
UINT8 h = 0, m = 0, s = 0 ;

   CHAR buffer[40]           ;
   CHAR *ptr2                ;
   char rom *rptr              ;

while(1)
   {   
   // if (counter % 5 == 0)
   //   if (++seconds % 60 == 0)
   //      seconds = 0;
   //   if (++minutes % 60 == 0)
   //      {   if (++hours > 12) hours = 0;
   //            minutes = 0; 
   //      }
sprintf(buffer, "%02u:%02u:%02u", hours, minutes, seconds);
printf("\r\n Time : %s", buffer);
sscanf(buffer,  "%02u:%02u:%02u", &h,  &m,  &s);
fprintf(ASTID, "\r\n Counting : %d %02u:02u:%02u", counter++, h,m,s);
delay_ms(200);
   }   return(0);
}

_________________
Thanks in advance ...
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 01, 2008 12:10 pm     Reply with quote

I didn't analyze your code, but adding this statement to your program
may help. This feature is available in vs. 4.xxx of the CCS compiler.
Code:
#device PASS_STRINGS=IN_RAM

See this post for an example:
http://www.ccsinfo.com/forum/viewtopic.php?t=34302&start=5
robinaspey



Joined: 01 Oct 2008
Posts: 4
Location: England (for time being)

View user's profile Send private message

Sscanf code (Mark Norton)
PostPosted: Thu Oct 02, 2008 5:00 am     Reply with quote

Adding the directive to pass strings in RAM certainly helped the program
compile but I havent so far managed to get the variables to copy the data
using the sscanf function (version with variable argument list). I will keep picking through it - the current return values are all zero so I guess it may be the bug pointed to (if it is a bug) by the previous posters.
_________________
Thanks in advance ...
dbotkin



Joined: 08 Sep 2003
Posts: 197
Location: Omaha NE USA

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Oct 23, 2008 5:00 pm     Reply with quote

Yeah, me too. This:

Code:

sprintf(sbuffer,"cn djkfr n /S30\n\r");
x = sscanf(sbuffer, "/%C%d%", &cmd, &param);
printf("sscanf() sez: x=%u, cmd=%X, param=%u\n\r", x, cmd, param);


gives me a compile error "Expecting a close paren" after &cmd in the sscanf() call. I'm not a "real" C programmer, so it's probably just something I don't get yet. Pointers? I can read, even if it sometimes takes a while to comprehend... Smile
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 23, 2008 5:16 pm     Reply with quote

For everyone:
If you say it doesn't compile, you need to post your compiler version.

Also say if you're trying to compile the code in Mark's original post
or the shorter version that he posted later.

Tell if you're using Mark's test program or your own test program.
If it's your own, then post it.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group