view gsm-fw/g23m-aci/aci/ati_prs.c @ 976:ca65f5adf1af

rvinterf: print old ASCII GPF traces emitted by 20020917 firmware on D-Sample
author Mychaela Falconia <falcon@ivan.Harhan.ORG>
date Sun, 29 Nov 2015 05:22:41 +0000
parents e7250023ca12
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-F&D (8411)
|  Modul   :  ATI
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  AT Command parameter parser
+----------------------------------------------------------------------------- 
*/ 

#ifndef ATI_PRS_C
#define ATI_PRS_C

#include "config.h"
#include "fixedconf.h"
#include "condat-features.h"
#include "aci_conf.h"

#include "aci_all.h"

#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>

#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"
#include "aci_prs.h"

#ifdef GPRS
  #include "gaci_cmh.h"
#endif /* GPRS */

#include "aci_lst.h"
#include "ati_int.h"

#ifdef OPTION_RELATIVE
LOCAL ULONG offset;
#endif

static UBYTE parse_index = 0;
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseBin           |
+--------------------------------------------------------------------+

  PURPOSE : parse binary value

*/

GLOBAL char *parseBin (int digits, char *b, SHORT *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND *b >= '0' AND *b <= '1')
    {
        found++;
        *i *= 2;
        *i += *b - '0';
        b++;
    }

    return ((found) ? b : 0);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseHex           |
+--------------------------------------------------------------------+

  PURPOSE : parse hexadecimal value

*/

GLOBAL char *parseHex (int digits, char *b, UBYTE *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND ((*b >= '0' AND *b <= '9') OR
                        (*b >= 'a'  AND *b <= 'f') OR
                        (*b >= 'A'  AND *b <= 'F')))
    {
        found++;
        *i *= 16;
        if (*b >= '0' AND *b <= '9')
            *i += *b - '0';
        if (*b >= 'a' AND *b <= 'f')
            *i += *b - 'a' + 10;
        if (*b >= 'A' AND *b <= 'F')
            *i += *b - 'A' + 10;
        b++;
    }

    return ((found AND found <= 2) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseHexToLong     |
+--------------------------------------------------------------------+

  PURPOSE : parse hexadecimal value

*/

GLOBAL char *parseHexToLong (int digits, char *b, LONG *i)
{
    *i = 0;
    while (digits-- AND ((*b >= '0' AND *b <= '9') OR
                        (*b >= 'a'  AND *b <= 'f') OR
                        (*b >= 'A'  AND *b <= 'F')))
    {
        *i *= 16;
        if (*b >= '0' AND *b <= '9')
            *i += *b - '0';
        if (*b >= 'a' AND *b <= 'f')
            *i += *b - 'a' + 10;
        if (*b >= 'A' AND *b <= 'F')
            *i += *b - 'A' + 10;
        b++;
    }

    return ( digits EQ 0 ? 0 : b );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseEnum          |
+--------------------------------------------------------------------+

  PURPOSE : parse enum value

*/

GLOBAL char *parseEnum (int digits, char *b, int *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND *b >= '0' AND *b <= '9')
    {
        found++;
        *i *= 10;
        *i += *b - '0';
        b++;
    }

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseShort         |
+--------------------------------------------------------------------+

  PURPOSE : parse Short value

*/

GLOBAL char *parseShort (int digits, char *b, SHORT *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND *b >= '0' AND *b <= '9')
    {
        found++;
        *i *= 10;
        *i += *b - '0';
        b++;
    }

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseStr           |
+--------------------------------------------------------------------+

  PURPOSE : parse string value

*/

GLOBAL char *parseStr (int digits, char *b, char *s)
{
    int found = 0;

    *s = 0;
    if (*b NEQ '"')
        return 0;
    b++;
    while (digits-- AND *b AND *b >= 0x20)
    {
        found++;
        if (*b EQ '"')
        {
            *s = 0;
            b++;
            break;
        }
        if (*b EQ '\\')
        {
            b = parseHex(2,b+1,(UBYTE *) s); /* ES!! ZERO ?           */
            if (!b)
                return 0;
            s++;
        }
        else
            *s++ = *b++;
    }
    if(*(b-1) NEQ '"')
      return 0;
    *s = 0;                             /* zero terminated          */

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseZStr          |
+--------------------------------------------------------------------+

  PURPOSE : parse string value

*/

GLOBAL char *parseZStr (int digits, char *b, char *s)
{
    int found = 0;

    *s = 0;
    if (*b NEQ '"')
        return 0;
    b++;
    while (digits--)
    {
        found++;
        if (*b EQ '"')
        {
            *s = 0;
            b++;
            break;
        }
        if (*b EQ '\\')
        {
            b = parseHex(2,b+1,(UBYTE *) s); /* ES!! ZERO ?           */
            if (!b)
                return 0;
            s++;
        }
        else
            *s++ = *b++;
    }
    if(*(b-1) NEQ '"')
      return 0;
    *s = 0;                             /* zero terminated          */

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseNStr          |
+--------------------------------------------------------------------+

  PURPOSE : parse string value and if not numeric returns error

*/

GLOBAL char *parseNStr (int digits, char *b, char *s)
{
    int found = 0;

    *s = 0;
    if (*b NEQ '"')
        return 0;
    b++;
    while (digits-- AND *b AND *b >= 0x20)
    {
        found++;
        if (*b EQ '"')
        {
            *s = 0;
            b++;
            break;
        }
        if (*b EQ '\\')
        {
            b = parseHex(2,b+1,(UBYTE *) s); /* ES!! ZERO ?           */
            if (!b)
                return 0;
            s++;
        }
        if ( *b > '9' OR *b < '0')
	    return 0; /*check if numeric value*/
	else
            *s++ = *b++;
    }
    if(*(b-1) NEQ '"')
      return 0;
    *s = 0;                             /* zero terminated          */

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseASCII         |
+--------------------------------------------------------------------+

  PURPOSE : parse ASCII value

*/

GLOBAL char *parseASCII (int digits, char *b, char *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND *b NEQ ' ' AND *b NEQ ',' AND *b NEQ ';' )
    {
        found++;
        *i = *b;
        i++;
        b++;
    }

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseQASCII        |
+--------------------------------------------------------------------+

  PURPOSE : parse ASCII value and terminate with 0

*/

GLOBAL char *parseQASCII (int digits, char *b, char *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND *b NEQ ',' AND *b NEQ ';' AND *b NEQ '\0')
    {
        found++;
        *i = *b;
        i++;
        b++;
    }

    if (found)
    {
      *i = 0;
      return (b);
    }

    return (NULL);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseStrLen        |
+--------------------------------------------------------------------+

  PURPOSE : parse sting, return length and startpoint

*/

GLOBAL char *parseStrLen (USHORT *len, char *b, char **p)
{
  *len = 0;
  if( *b EQ '"' )
    b++;

  /* Check if the string is a null string like "" */
  if( *b EQ '"' )
  {
    b++;

   /* return new buffer position without setting p, thereby omitting the parameter */
    return b; 
  }

  *p = b;

  while ( *b NEQ '\0' AND *b NEQ ',' AND *b NEQ ';' AND *b NEQ '"' )
  {
    (*len)++;
    b++;
  }
 
  if(*b EQ '"')
  {
    b++;
  }

  return ((*len) ? b : 0);
}


#ifdef GPRS

/*
+--------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ACI_PRS            |
| STATE   : devellopment                ROUTINE : parseExpo          |
+--------------------------------------------------------------------+

  PURPOSE : parse exponential expresion (ex. 2E3)

*/

GLOBAL char *parseExpo( int digits, char *b, T_PS_ber *e )
{
  BOOL valid = FALSE;

  e->ratio_mant = 0;
  e->ratio_exp  = 0;
  if( *b EQ '"' ) /* start of string */
  {
    b++;
    while( digits-- AND *b >= '0' AND *b <= '9' )
    {
      e->ratio_mant *= 10;
      e->ratio_mant += *b - '0';
      b++;
    }
    if( *b EQ 'E' )
    {
      b++;
      while( digits-- AND *b >= '0' AND *b <= '9' )
      {
        e->ratio_exp *= 10;
        e->ratio_exp += *b - '0';
        b++;
        valid = TRUE;
      }
      
      if( *b EQ '"' ) /* end of string */
      {
        b++;
      }
      else
      {
        valid = FALSE;
      }
      	
    }
    else
    {
      valid = FALSE;
    }
  }
  else
  {
    valid = FALSE;
  }

  return ((valid) ? b : 0);

} /* END parseExpo(...) */

/*
+--------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ACI_PRS            |
| STATE   : Finished                    ROUTINE : parseCid_list      |
+--------------------------------------------------------------------+

  PURPOSE : Parse a list of Cids. If the parsing is sucessfull the 
            number of parsed cids is returned otherwise -1 is returned.

*/
GLOBAL char *parseCid_list(char *b, U8 *cid_list_length, U8 *cid_list)
{
  U8    no_of_cids;
  char *end;

  /* Parse all cids into the cid_list */
  no_of_cids = 0;
  do
  {

    /* If it's not the first cid remove the "," */
    if( no_of_cids )
      b++;

    /* Set the entry to omitted. */
    cid_list[no_of_cids] = PDP_CONTEXT_CID_OMITTED;

    /* Parse the value */
    cid_list[no_of_cids] = (U8) strtol( b, &end, 10 );
    b = end;

    /* If a cid is omitted no cids must be specified at all. */
    if( cid_list[no_of_cids] EQ PDP_CONTEXT_CID_OMITTED )
    {
      if( no_of_cids NEQ 0 )
      {
        /* Don't accept omitted cids inside if it's not the first (ex. 1,,2,3 is not allowed). */
        cmdCmeError( CME_ERR_OpNotSupp );
        return( NULL );
      }
      /* Break the while */
      break;
    }
    if( (!b) OR 
        (cid_list[no_of_cids] <  PDP_CONTEXT_CID_MIN) OR 
        (cid_list[no_of_cids] >  PDP_CONTEXT_CID_MAX) OR 
        (no_of_cids           >= PDP_CONTEXT_CID_MAX) )
    {
      cmdCmeError( CME_ERR_OpNotSupp );
      return( NULL );
    }
    no_of_cids++;
  }
  
  while( *b EQ ','  AND
    no_of_cids < *cid_list_length );
  
  cid_list[no_of_cids+1] = PDP_CONTEXT_CID_INVALID;

  *cid_list_length = no_of_cids;
  return( b );

}

#endif /* GPRS */

/*
+----------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ATI_PRS              |
| STATE   : -                           ROUTINE : parsePointerToString |
-----------------------------------------------------------------------+

  PURPOSE : Parse pointer to input string. returns pointer to end of string.

*/
GLOBAL char *parsePointerToString(char chars, char *b, char **p_begin)
{
  if( b AND *b EQ '"' )
  {
    b++;
    *p_begin = b;
    
    while (chars-- AND *b AND *b NEQ '"')
    {
      b++;
    }
    if( *b EQ '"' )
    {
      b++;
    }
    else
    {
      if( !chars )
      {
        b = NULL;
      }
    }
  }

  return b;
}

/*
+----------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ATI_PRS              |
| STATE   : -                           ROUTINE : StrToU16             |
-----------------------------------------------------------------------+

  PURPOSE : Parse string value to U16.

*/

char *StrToU16(char *p_str, U16 *p_result)
{
  U32 val = 0;
  
  if( p_str )
  {
    if( *p_str >= '0' AND *p_str <= '9' )
    {
      while( *p_str >= '0' AND *p_str <= '9' )
      {
        val *= 10;
        val += (int)(*p_str - '0');
        p_str++;
      }
    }
  }

  if( val <= 0xffff ) /* 0xffff = max value of U16 */
  	*p_result = (U16)(val);
  else
  	p_str = NULL;
  
  return p_str;
  
}

/*
+---------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ATI_PRS             |
| STATE   : -                           ROUTINE : parseDSNP_U16       |
----------------------------------------------------------------------+

  PURPOSE : parse dot-separated numeric parameters from the 
            input string to an array of U8.
            
            ex. input p_in = "192.124.13.3"
                output p_out = {192,124,13,3} 

*/
GLOBAL char *parseDSNP_U16( char blocks, char *p_in, U16 *p_out )
{
  if( p_in AND p_out )
  {
    if( *p_in EQ '.' ) p_in++;
    while( blocks-- AND *p_in NEQ 0x00 )
    {
      p_in = StrToU16(p_in, p_out);
      
      if( p_in AND blocks AND *p_in EQ '.' )
      {
        p_in++;
        p_out++;
      }
      else
        break;
    }
  }
  return p_in;
}

/*
+---------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ATI_PRS             |
| STATE   : -                           ROUTINE : parseIPv4Address    |
----------------------------------------------------------------------+
*/
GLOBAL char *parseIPv4Address(char *p_in, U8 * p_ip_addr, U8 * is_ip_valid)
{
  U16  ip_addr[4];
  char i;
  char *p_out = NULL;

  if( p_in AND p_ip_addr )
  {
    p_out = parseDSNP_U16(4, p_in, ip_addr);
    for(i=0; i<4; i++)
    {
      if(ip_addr[i] <= 255)
      {
        p_ip_addr[i] = (U8) ip_addr[i];
      }
      else
      {
        p_out = NULL;
      }

    }
  }
  * is_ip_valid = (p_out NEQ NULL);

  return p_out;
}

/*
+---------------------------------------------------------------------+
| PROJECT : UMTS                        MODULE  : ATI_PRS             |
| STATE   : -                           ROUTINE : parseIPv6Address    |
----------------------------------------------------------------------+
*/
GLOBAL char *parseIPv6Address(char *p_in, U8 *p_ip_addr, U8 * is_ip_valid)
{
  U16  ip_addr[16];
  char i;
  char *p_out = NULL;

  if( p_in AND p_ip_addr )
  {
    p_out = parseDSNP_U16(16, p_in, ip_addr);
    for(i=0; i<16; i++)
    {
      if(ip_addr[i] > 255)
        p_out = NULL;
      else
        p_ip_addr[i] = (U8) ip_addr[i];
    }
  }

  * is_ip_valid = (p_out NEQ NULL);

  return p_out;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parse              |
+--------------------------------------------------------------------+

  PURPOSE : parse AT command parameter

*/

GLOBAL char *parse (char *b, char *f, ...)
{
  char fc;
  USHORT *i;

#ifdef GPRS
  U8      *j;
#endif /* GPRS */
  LONG    digits = -1;
  BOOL value_is_valid;
 /*lint -e516 -e10*/
  va_list varpars;

  va_start (varpars, f);        /* Initialize variable arguments. */

  parse_index=0;
  while ((fc = *f++) NEQ 0)
  {
    parse_index++;              /* Save the position of current parsing item */
    value_is_valid = TRUE;
    if (islower(fc))
    {
      if (*b EQ 0 OR *b EQ ';')
      {
        va_end (varpars);        /* Reset variable arguments.      */
        return b;
      }
      if (*b EQ ',')
      {
        b++;
        value_is_valid = FALSE;
      }
    }

    switch (toupper(fc))
    {
      case 'B':
        if (value_is_valid)
          b = parseBin(-1,b,va_arg (varpars, short*));
        else
          (void)va_arg (varpars, short*);
        break;
      
      case 'X':
        if (value_is_valid)
          b = parseHex(-1,b,va_arg (varpars, unsigned char*));
        else
          (void)va_arg (varpars, short*);
        break;
      
      case 'Y':
        if (value_is_valid)
          b = parseHexToLong(-1,b,va_arg (varpars, long*));
        else
          (void)va_arg (varpars, short*);
        break;
      
      case 'D':
        if (value_is_valid)
          b = parseEnum(-1,b,va_arg (varpars, int*));
        else
          (void)va_arg (varpars, int*);
        break;
      
      case 'R':
        if (value_is_valid)
          b = parseShort(-1,b,va_arg (varpars, short*));
        else
          (void)va_arg (varpars, short*);
        break;
      
      case 'S':
        if (value_is_valid)
        {
          digits=va_arg (varpars, long);
          b = parseStr(digits,b,va_arg (varpars, char*));
        }
        else
        {
          (void)va_arg (varpars, long);
          (void)va_arg (varpars, char*);
        }
				break;
      
			case 'N':
        if (value_is_valid)
        {
          digits=va_arg (varpars, long);
   				b = parseNStr(digits,b,va_arg (varpars, char*));
        }
        else
        {
          (void)va_arg (varpars, long);
          (void)va_arg (varpars, char*);
        }
        break;
      
      case 'Z':
        if (value_is_valid)
        {
          char*   c    = b;
          USHORT* plen = NULL;

          char*   cmdPtr;
          USHORT  cmdLen;

          digits = va_arg ( varpars, long );
          cmdLen = va_arg ( varpars, unsigned );
          cmdPtr = va_arg ( varpars, char* );
          plen   = va_arg ( varpars, unsigned short*);
          b      = parseZStr
                     ( MINIMUM (digits, cmdLen - ( b - cmdPtr )),
                       b, va_arg ( varpars, char* ) );

          if ( plen NEQ NULL )
          {
            if ( b NEQ NULL )
              *plen = b - c - 2; /* a string always includes two characters '"' */
            else
              *plen = 0;
          }
        }
        else
        {
          (void)va_arg (varpars, long);
          (void)va_arg (varpars, unsigned short*);
          (void)va_arg (varpars, char*);
        }
        break;
      
      case 'A':
        if (value_is_valid)
        {
          digits=va_arg (varpars, long);
          b = parseASCII(digits,b,va_arg (varpars, char*));
        }
        else
        {
          (void)va_arg (varpars, long);
          (void)va_arg (varpars, char*);
        }
        break;
      
      case 'Q':
        if (value_is_valid)
        {
          digits=va_arg (varpars, long);
          b = parseQASCII(digits,b,va_arg (varpars, char*));
        }
        else
        {
          (void)va_arg (varpars, long);
          (void)va_arg (varpars, char*);
        }
        break;

      case 'L':
        if (value_is_valid)
        {
          i = va_arg(varpars, unsigned short*);
          b = parseStrLen (i,b,va_arg(varpars, char**));
        }
        else
        {
          (void)va_arg (varpars, int*);
          (void)va_arg (varpars, char**);
        }
        break;

#ifdef GPRS

      case 'E':
        if (value_is_valid)
        {/*lint -e78 -e26 -e530*/
          b = parseExpo( -1, b, va_arg(varpars, T_PS_ber*));
        }
        else
        {
          (void)va_arg (varpars, T_PS_ber*);
        }
        break;

#endif

      case 'C':
        if (value_is_valid)
        {
          b = parseByte( -1, b, va_arg(varpars, unsigned char*));
        }
        else
        {
          (void)va_arg (varpars, unsigned char*);
        }
        break;

#ifdef GPRS

      case 'I': /* Parse cid_list */
        if( value_is_valid )
        {
          j = va_arg(varpars, unsigned char*);

          b = parseCid_list( b, j, va_arg(varpars, unsigned char*) );
        }
        break;
#endif /* GPRS */

      case 'P': /* Parse pointer to string */
        if( value_is_valid )
        {
          b = parsePointerToString( (char)-1, b, va_arg(varpars, char**) );
        }
        break;

      case '*': /* Parse '*' */
        if( value_is_valid )
        {
          if( *b NEQ '*' )
          {
            return 0;
          }
          b++;
        }
        break;

      case '#': /* Parse '#' */
        if( value_is_valid )
        {
          if( *b NEQ '#' )
          {
            return 0;
          }
          b++;
        }
        break;
     }
    if (!b)
    {
      va_end (varpars);              /* Reset variable arguments.      */
      return 0;
    }

    if (*f AND *b EQ ',' AND value_is_valid)
    {
      b++;
    }
    else if (*b AND *b NEQ ';' AND *b NEQ ',' AND value_is_valid)  /* if comma or semicolon is missing */
    {
      TRACE_EVENT ("missing separator detected, aborting parse!");
      va_end (varpars);
      return 0;
    }
  }
  if (*b AND *b NEQ ';')
  {
    va_end (varpars);              /* Reset variable arguments.      */
    return 0;
  }
  va_end (varpars);              /* Reset variable arguments.      */
 /*lint +e516 +e10*/
  return b;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parse              |
+--------------------------------------------------------------------+

  PURPOSE : get last parsed index (to determinate which component was malicious)

*/

GLOBAL UBYTE get_parse_index ()
{
  return parse_index;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseByte(U8)      |
+--------------------------------------------------------------------+

  PURPOSE : parse U8 value

*/

GLOBAL char *parseByte (int digits, char *b, U8 *i)
{
    int found = 0;

    *i = 0;
    while (digits-- AND *b >= '0' AND *b <= '9')
    {
        found++;
        *i *= 10;
        *i += *b - '0';
        b++;
    }

    return ((found) ? b : 0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_PRS            |
| STATE   : code                        ROUTINE : parseTimeStamp              |
+--------------------------------------------------------------------+

  PURPOSE : Parse time stamp format in "yy/MM/dd,hh:mm:ss±zz"

*/

GLOBAL UBYTE parseTimeStamp( char *p_in,U8 *years,U8 *months,U8 *days,
                             U8 *hrs, U8 *mins,U8 *secs, char *sign, U8 *time_zone )
{
  if( p_in[2] NEQ '/' OR  p_in[5] NEQ '/' OR p_in[8] NEQ ',' OR p_in[11] NEQ ':' OR p_in[14] NEQ ':' )
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[0], years))
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[3], months))
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[6], days))
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[9], hrs))
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[12], mins))
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[15], secs))
  {
    return NO_TIME_STAMP_FIELD;
  }
  *sign = p_in[17];

  if(*sign NEQ '+' AND  *sign NEQ '-' )
  {
    return NO_TIME_STAMP_FIELD;
  }
  if(!parseByte (2, &p_in[18], time_zone))
  {
    return NO_TIME_STAMP_FIELD;
  }

 return MAX_TIME_STAMP_FIELDS; 
}

#endif /* ATI_PRS_C */