This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Source Code for Scanf

I have been trying to reroute scanf() on CCS. I succesfully rerouted printf(), but I had help with a tutorial. I just had to modify code for my board. 

My first guess in the first step to rerouting scanf(() is seeing the source code for it. Does any one know how I could go about this?

The include files on my program is:

msp430.h

stdio.h

string.h

  • Hi Rodney,

    Yes you'd have to do something similar for scanf. The source code for it comes with the compiler package. For example, the rts lib source dir for the MSP430 compiler that comes with CCSv6 should be in <CCS INSTALL DIR>\ccsv6\tools\compiler\ti-cgt-msp430_4.4.3\lib\src. See the fscanf.c file in there.

    thanks

    ki

  • I found fscanf.c in that directory. The scanf() in there goes in to other functions. __TI_scanfi() is the "main scanf handling routing." This functions goes in to other functions which is unclear.

    I was expecting functions to read from I/O and place input into buffers. Particularly, I was expecting fgetc() and fgets(). 

    For the printf() redirect, fputc() and fputs() was overridden. 

    int fputc(int _c, register FILE *_fp)
    {
    	while(!(UCA1IFG&UCTXIFG));
    		UCA1TXBUF = (unsigned char) _c;
    
    		return((unsigned char)_c);
    }
    int fputs(const char *_ptr, register FILE *_fp)
    {
    	unsigned int i, len;
    
    	len = strlen(_ptr);
    
    	for(i=0 ; i<len ; i++) {
    		while(!(UCA1IFG&UCTXIFG));
    		UCA1TXBUF = (unsigned char) _ptr[i];
    	}
    
      return len;
    }

    The link you gave redirects printf() another way with freopen().

    How does scanf() access I/O?

  • Hi Rodney,
    I will move this thread to the compiler forum where the experts there can help you best.

    Thanks
    ki
  • scanf calls __TI_scanfi to handle the formatting. Through callback functions, __TI_scanfi eventually calls fgetc and ungetc. If you replace these two functions as you have replaced fputc and fputs, you should be able to read from your own device. See the source code in fscanf.c
  • Thanks, Ki-soo Lee for moving this tread.

    Hi Archaeologist,

    I could not find __TI_scanfi() in my <CCS INSTALL DIR>. However, I found a reference of __TI_scanfi() in _scanfi.c

    _scanfi.c
    /*****************************************************************************/
    /*  _SCANFI.C v4.4.4                                                         */
    /*                                                                           */
    /* Copyright (c) 1995-2015 Texas Instruments Incorporated                    */
    /* http://www.ti.com/                                                        */
    /*                                                                           */
    /*  Redistribution and  use in source  and binary forms, with  or without    */
    /*  modification,  are permitted provided  that the  following conditions    */
    /*  are met:                                                                 */
    /*                                                                           */
    /*     Redistributions  of source  code must  retain the  above copyright    */
    /*     notice, this list of conditions and the following disclaimer.         */
    /*                                                                           */
    /*     Redistributions in binary form  must reproduce the above copyright    */
    /*     notice, this  list of conditions  and the following  disclaimer in    */
    /*     the  documentation  and/or   other  materials  provided  with  the    */
    /*     distribution.                                                         */
    /*                                                                           */
    /*     Neither the  name of Texas Instruments Incorporated  nor the names    */
    /*     of its  contributors may  be used to  endorse or  promote products    */
    /*     derived  from   this  software  without   specific  prior  written    */
    /*     permission.                                                           */
    /*                                                                           */
    /*  THIS SOFTWARE  IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS    */
    /*  "AS IS"  AND ANY  EXPRESS OR IMPLIED  WARRANTIES, INCLUDING,  BUT NOT    */
    /*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR    */
    /*  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT    */
    /*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    */
    /*  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL  DAMAGES  (INCLUDING, BUT  NOT    */
    /*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,    */
    /*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY    */
    /*  THEORY OF  LIABILITY, WHETHER IN CONTRACT, STRICT  LIABILITY, OR TORT    */
    /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE    */
    /*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     */
    /*                                                                           */
    /*****************************************************************************/
    
    /*****************************************************************************/
    /*    This file contains the main routines that all three variations of the  */
    /*    scanf function use.  The main function in the file is __TI_scanfi, and */
    /*    the other functions here are called by it.                             */
    /*                                                                           */
    /* FUNCTIONS:                                                                */
    /*    __TI_scanfi        -  The main scanf handling routine                  */
    /*    _sget_conv     -  Read the format flags into the _SFIELD pointer sfield*/
    /*    _sget_scanset  -  Read in the scanset from the format statement        */
    /*    _sproc_int     -  Read an integer string into a temporary string       */
    /*    _sproc_float   -  Read a float string into a temporary string          */
    /*    _sproc_str     -  Copy a string from the input source to a temporary   */
    /*                      string                                               */
    /*    _sproc_lb      -  Process the %[ conversion                            */
    /*    _sset_arg      -  Assign the converted value to the next argument      */
    /*****************************************************************************/
    #include <stdio.h>
    #include "format.h"
    #include <stdarg.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <ctype.h>
    #include <string.h>
    #include <limits.h>
    
    #ifdef LLONG_MAX
    _CODE_ACCESS long long strtoll(const char *_st, char **_endptr, int _base);
    _CODE_ACCESS unsigned long long strtoull(const char *_st, char **_endptr,
    					 int _base);
    #endif
    
    _CODE_ACCESS long double strtold(const char *st, char **endptr);
    
    static int _sget_conv(char **_format, _SFIELD *sfield);
    #if !defined(MINIMAL)
    static int _sget_scanset(_SFIELD *sfield, char **_format);
    #endif
    static int _sproc_int(int w_counter, int (*_inpchar)(void **inp),
                           void (*_uninpchar)(void **inp, int outchar),
                           char *tmpptr, char conv, void **inp, int *num_read);
    #if !defined(NOFLOAT) && !defined(MINIMAL)
    static int _sproc_float(int w_counter, int (*_inpchar)(void **inp),
                             void (*_uninpchar)(void **inp, int outchar),
                             char *tmpptr, char conv, void **inp, int *num_read);
    #endif
    static int _sproc_str(int w_counter, int (*_inpchar)(void **inp),
                           void (*_uninpchar)(void **inp, int outchar),
                           char *tmpptr, char conv, void **inp, int *num_read);
    #if !defined(MINIMAL)
    static int _sproc_lb(int (*_inpchar)(void **inp),
                          void (*_uninpchar)(void **inp, int outchar),
                          char *tmpptr, _SFIELD *sfield, void **inp, int *num_read);
    #endif
    static void _sset_arg(_SFIELD *sfield, va_list *_ap, char *tmpbuf);
    
    #if !defined(NOFLOAT) && !defined(MINIMAL)
    #define _SCANFI __TI_scanfi
    #elif defined(NOFLOAT)
    #define _SCANFI __TI_scanfi_nofloat
    #elif defined(MINIMAL)
    #define _SCANFI __TI_scanfi_minimal
    #endif
    
    /*****************************************************************************/
    /* _SCANFI  -  The main scanf handling routine                               */
    /*                                                                           */
    /*    This function parses all non-conversion characters in the format       */
    /*    string, passes control to the appropriate function when a '%' is       */
    /*    encountered, then calls _SSET_ARG, which assignes the result to the    */
    /*    next argument.                                                         */
    /*                                                                           */
    /*    For multi-threaded applications, when this function is called on       */
    /*    behalf of scanf, fscanf, vscanf, or vfscanf, the call site should be   */
    /*    enclosed in a critical section that guarantees single-threaded access  */
    /*    to the file stream.                                                    */
    /*                                                                           */
    /*****************************************************************************/
    int _SCANFI(void *inp, const char *_format, va_list _ap, 
                int (*_chkmbc)(void **inp, char **_format, int *num_read),
                int (*_inpchar)(void **inp), 
                void (*_uninpchar)(void **inp, int outchar))
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       _SFIELD  sfield;
       char     tmpbuf[256],
               *tmpptr,
               *f_ptr        = (char *)_format;
       int      num_assigned =  0,
                inchar,
                num_read     =  0,
                stat         =  0;
    
       /*------------------------------------------------------------------------*/
       /* If the first character in the format string is a white space character */
       /* parse the format string until a non-white space character is found.    */
       /* Do the same for the input, but put the first non-white space character */
       /* back onto the input stream when finished.                              */
       /*------------------------------------------------------------------------*/
       if (isspace(*f_ptr))
       {
          for (;isspace(*f_ptr);f_ptr++);
    
          inchar = _inpchar(&inp);
          if (inchar == EOF) return EOF;
          num_read++;
    
          for (;isspace(inchar); inchar = _inpchar(&inp), num_read++);
    
          _uninpchar(&inp, inchar);
          num_read--;
    
          if (inchar == EOF) return EOF;
       }
    
       while (1)
       {
          /*---------------------------------------------------------------------*/
          /* Initialize sfield                                                   */
          /*---------------------------------------------------------------------*/
          memset(&sfield, 0, sizeof(_SFIELD));
          sfield.fwidth = -1;
    
          /*---------------------------------------------------------------------*/
          /* Call _chkmbc to compare the ordinary characters in the format       */
          /* string to the input.  If the end of the format string is reached,   */
          /* or a mismatch occurs, return the number of successful conversions.  */
          /* If an input error occurs before any conversions, return EOF.        */
          /* Otherwise a '%' has been seen, so call _sget_conv to process it.    */
          /*---------------------------------------------------------------------*/
          switch (_chkmbc(&inp, &f_ptr, &num_read))
          {
             case  EOF   : return num_assigned ? num_assigned : EOF;
       
             case  0     : return num_assigned;
       
             case  1     :  _sget_conv(&f_ptr, &sfield);
          }
       
          tmpptr = tmpbuf;
    
          /*---------------------------------------------------------------------*/
          /* Unless the conversion specifier is a [, c, or n, skip to the next   */
          /* non-white space character in the input.                             */
          /*---------------------------------------------------------------------*/
    #if !defined(MINIMAL)
          if (sfield.conv != '[' && sfield.conv != 'c' && sfield.conv != 'n')
    #else
          if (sfield.conv != 'c')
    #endif
          {
             inchar = _inpchar(&inp);
             num_read++;
        
             for (;isspace(inchar); inchar = _inpchar(&inp), num_read++);
        
             _uninpchar(&inp, inchar);
             num_read--;
    
             /*---------------------------------------------------------------*/
             /* If we've encountered the end of the stream AND we haven't     */
             /* matched anything yet, return EOF.                             */
             /*---------------------------------------------------------------*/
             if (inchar == EOF && num_read == 0) return EOF;
          }
          else
          {
             /*---------------------------------------------------------------*/
             /* If we've encountered the end of the stream AND we haven't     */
             /* matched anything yet, return EOF.                             */
             /*---------------------------------------------------------------*/
             inchar = _inpchar(&inp);
             _uninpchar(&inp, inchar);
             if (inchar == EOF && num_read == 0) return EOF;
          }
          
          /*---------------------------------------------------------------------*/
          /* The flags have been set in sfield, so process the conversion by     */
          /* calling the appropriate function.                                   */
          /*---------------------------------------------------------------------*/
          switch (sfield.conv)
          {
    #if !defined(MINIMAL)
             case  'X'   :  /* Change X to x because _sproc_int checks sfield.conv,
                               and we can save two bytes by doing this.  Surely 
                               this instruction will take at least that many 
                               bytes... */
                            sfield.conv = 'x';
             case  'i'   :
             case  'p'   :  
             case  'u'   :
    #endif
             case  'x'   :
             case  'o'   :
             case  'd'   :  stat = _sproc_int(sfield.fwidth, _inpchar, _uninpchar, 
                                             tmpptr, sfield.conv, &inp, &num_read); 
                            break;
    
    #if !defined(NOFLOAT) && !defined(MINIMAL)
             case  'f'   :
             case  'e'   :
             case  'E'   :
             case  'g'   :
             case  'G'   :  stat = _sproc_float(sfield.fwidth, _inpchar, _uninpchar,
                                         tmpptr, sfield.conv, &inp, &num_read);
                            break;
    #endif
    
             case  'c'   :  
             case  's'   : {
                              char *stptr = (sfield.flags & _SFSTAR) ?
                                             NULL : va_arg(_ap, char*);
    
                              stat = _sproc_str(sfield.fwidth, _inpchar, _uninpchar,
                                         stptr, sfield.conv, &inp, &num_read);
                           }
                           break;
    
    #if !defined(MINIMAL)
             case  '['   :  stat = _sproc_lb(_inpchar, _uninpchar, tmpptr, &sfield,
                                             &inp, &num_read);
                            break;
    #endif
    
             case  '%'   :  inchar = _inpchar(&inp);
                            if (inchar == '%')
                            {
                                stat = 1;
                                num_read++;
                            }
                            else
                            {
                                _uninpchar(&inp, inchar);
                                stat = inchar == EOF ? EOF : 0;
                            }
                            break;
    
    #if !defined(MINIMAL)
             case  'n'   :  stat = 1; /* %n cannot fail */
    #endif
          }
    
          /*---------------------------------------------------------------------*/
          /* When an error occurs, return now.  Failures are either input        */
          /* failures (due to running out of input) or matching failures (due to */
          /* inappropriate input for that directive).  If an input error occured */
          /* before any conversion, return EOF.  Otherwise, return the number of */
          /* conversions performed (possibly 0).  (%%, %n, and normal characters */
          /* in the format don't count, and neither do any conversions for which */
          /* the assignment has been suppressed.)                                */
          /*---------------------------------------------------------------------*/
          if (stat == 0 || stat == EOF)
              return num_assigned ? num_assigned : stat;
    
          /*---------------------------------------------------------------------*/
          /* Now, call the function to handle the actual assignment, or if there */
          /* is no assignment to take place, process it here.                    */
          /*---------------------------------------------------------------------*/
          switch (sfield.conv)
          {
    #if !defined(MINIMAL)
             case  'i'   :
             case  'p'   : 
             case  'u'   :
    #endif
             case  'd'   :  
             case  'x'   :
             case  'o'   :  
    #if !defined(NOFLOAT) && !defined(MINIMAL)
             case  'e'   :
             case  'f'   :
             case  'g'   :
             case  'E'   :
             case  'G'   :
    #endif
                            _sset_arg(&sfield, &_ap, tmpbuf);
                            /* fallthrough */
    
             case  'c'   :
             case  's'   :
                            if ((!(sfield.flags & _SFSTAR))) num_assigned++;
                            break;
     
    #if !defined(MINIMAL)
             case  'n'   :  if (!(sfield.flags & _SFSTAR))
                               switch(sfield.flags & 
                                      (_MFH | _MFHH | _MFL | _MFLL | _MFI40))
                               {
                                  case  _MFH  :  *(va_arg(_ap, short int*)) =
                                                 (short int)num_read;
                                                 break;
     
                                  case  _MFHH :  *(va_arg(_ap, char*)) =
                                                 (char)num_read;
                                                 break;
     
                                  case _MFL   :  *(va_arg(_ap, long int*)) =
                                                 (long int)num_read;
                                                 break;
    #ifdef LLONG_MAX
                                  case _MFLL  :  *(va_arg(_ap, long long int*)) =
                                                 (long long int)num_read;
                                                 break;
    #endif
    #ifdef __TI_INT40_T__
                                  case _MFI40 :  *(va_arg(_ap, __int40_t*)) =
                                                 (__int40_t)num_read;
                                                 break;
    #endif
                                  default     :  *(va_arg(_ap, int*)) =
                                                 num_read;
                                                 break;
                               }
                            break;
    
             case  '['   :  if (!(sfield.flags & _SFSTAR))
                            {
                               strcpy(va_arg(_ap, char *), tmpbuf);
                               num_assigned++;
                            }
    #endif
          }
       }
    
    }
    
    /*****************************************************************************/
    /* _SGET_CONV  -  Read the format flags into the _SFIELD pointer sfield      */
    /*                                                                           */
    /*    This function reads the characters directly after the '%' character,   */
    /*    and stores them as flags in sfield, a pointer to a _SFIELD structure.  */
    /*    These flags will later be used to process the conversion.              */
    /*                                                                           */
    /*****************************************************************************/
    static int _sget_conv(char **_format, _SFIELD *sfield)
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       char *strend = (*_format) + strlen(*_format);
    
       (*_format)++;                        /* Go to the character after the '%' */
    
    #if !defined(MINIMAL)
       /*------------------------------------------------------------------------*/
       /* If the next character in the format statement is a '*', set the        */
       /* _SFSTAR flag in sfield                                                 */
       /*------------------------------------------------------------------------*/
       if (**_format == '*')
       {
          _SET(sfield, _SFSTAR);
          (*_format)++;
       }
     
       /*------------------------------------------------------------------------*/
       /* If numerical characters follow, read them into a temporary string,     */
       /* convert it into a number, and store it as the field width in sfield    */
       /*------------------------------------------------------------------------*/
       {
           char  tmpbuf[8], *tmpptr = tmpbuf;
    
           for (;**_format>='0' && **_format<='9'; *(tmpptr++) = *((*_format)++));
           *tmpptr = '\0';
           
           if (strlen(tmpbuf)) sfield->fwidth = atoi(tmpbuf);
       }
     
       /*------------------------------------------------------------------------*/
       /* Set the h, l, or L flags if they were specified                        */
       /*------------------------------------------------------------------------*/
       switch (**_format)
       {
    #if !defined(NOFLOAT)
           case 'L': _SET(sfield, _MFLD); (*_format)++; break;
    #endif
           case 'h':
           {
               (*_format)++;
               if (**_format == 'h') { _SET(sfield, _MFHH); (*_format)++; }
               else _SET(sfield, _MFH);
               break;
           }
           case 'l': 
           {
    	   (*_format)++;
    	   if (**_format == 'l') { _SET(sfield, _MFLL); (*_format)++; }
    	   else _SET(sfield, _MFL);
           }
    #if __TI_INT40_T__
              case 'I':
              {
                 if ((*(*_format+1)) == '4' && (*(*_format+2)) == '0')
                 { _SET(sfield, _MFI40); (*_format) += 3; }
                 break;
              }
    #endif
       }
    #endif
    
       /*------------------------------------------------------------------------*/
       /* Read in the last character as the conversion specifier                 */
       /*------------------------------------------------------------------------*/
       sfield->conv = *((*_format)++);
    
    #if !defined(MINIMAL)
       /*------------------------------------------------------------------------*/
       /* For the '[' conversion, read in the scanset.  Return an EOF if         */
       /* _SGET_SCANSET fails.                                                   */
       /*------------------------------------------------------------------------*/
       if ((sfield->conv == '[') && _sget_scanset(sfield, _format)) return (EOF);
    #endif
    
       /*------------------------------------------------------------------------*/
       /* If we read past the end of the format string, return an error          */
       /*------------------------------------------------------------------------*/
       if (*_format > strend) return (EOF);
       else return (0);
    }
    
    #if !defined(MINIMAL)
    /*****************************************************************************/
    /* _SGET_SCANSET  -  Read in the scanset from the format statement           */
    /*                                                                           */
    /*    This function is called when the '[' conversion specifier has been     */
    /*    encountered.  It reads in the scanset from the format statement,       */
    /*    and stores it in sfield for later reference during the conversion.     */
    /*                                                                           */
    /*****************************************************************************/
    static int _sget_scanset(_SFIELD *sfield, char **_format)
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       char  *tmpptr  =  sfield->scanset;
    
       if (**_format == '^')
       {
          _SET(sfield, _SFCIRC);
          (*_format)++;
       }
    
       if (**_format == ']') *(tmpptr++) = *((*_format)++);
    
       while (**_format != ']' && **_format != '\0') *(tmpptr++) = *((*_format)++);
    
       *tmpptr = '\0';
       if (**_format == ']') (*_format)++;
       if (**_format == '\0') return (EOF);
    
       return(0);
    }
    #endif
    
    /*****************************************************************************/
    /* _SPROC_INT  -  Read an integer string into a temporary string             */
    /*                                                                           */
    /*    This function takes the next integer in character form from the        */
    /*    current input source, and copies it into a temporary string, where     */
    /*    it can later be converted into a numerical value.                      */
    /*                                                                           */
    /*    Returns:                                                               */
    /*                                                                           */
    /*        EOF if end-of-file was reached before a matching input sequence    */
    /*            (well-formed input item) was found (this is an input failure)  */
    /*                                                                           */
    /*        1   if an input item was found                                     */
    /*                                                                           */
    /*        0   if an input item was not found (this is a matching failure)    */
    /*                                                                           */
    /*****************************************************************************/
    static int _sproc_int(int w_counter, int (*_inpchar)(void **inp), 
                           void (*_uninpchar)(void **inp, int outchar), 
                           char *tmpptr, char conv, void **inp, int *num_read) 
    {
       /*------------------------------------------------------------------------*/
       /* Note: w_counter is a parameter that holds the field width.  When       */
       /*       the number of digits specified by w_counter has been read from   */
       /*       input, the function finishes.  w_counter is checked before each  */
       /*       read to make sure that it is not equal to zero, and it is        */
       /*       decremented after each read.  If no field width was specified,   */
       /*       w_counter will be equal to -1, in which case it will never       */
       /*       equal zero, and the function will read from input until it       */
       /*       encounters the first invalid character.                          */
       /*------------------------------------------------------------------------*/
    
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       int inchar, look_ahead_char;
       int bnum_read = *num_read;
       int seen_leading_zero = 0, seen_num = 0, base;
       int hex_conv = 0;
       int inchar_is_x = 0;
    
       static const _DATA_ACCESS char flit[] = "diouxp";
       static const _DATA_ACCESS char barr[] = {10, 0, 8, 10, 16, 16}; 
       
       /*------------------------------------------------------------------------*/
       /* Read in the next character                                             */
       /*------------------------------------------------------------------------*/
       inchar = _inpchar(inp);
       (*num_read)++;
    
       /*------------------------------------------------------------------------*/
       /* Accept the next character if it is a sign for the number               */
       /*------------------------------------------------------------------------*/
       if (w_counter != 0 && (inchar == '+' || inchar == '-'))
       {
          *(tmpptr++) = inchar;
          inchar = _inpchar(inp);
          (*num_read)++;
          w_counter--;
       }
    
       if (w_counter != 0)
       {
          /*---------------------------------------------------------------------*/
          /* Decide number base according to the conversion specifier            */
          /*---------------------------------------------------------------------*/
          base = barr[(const char *)strchr(&flit[0], conv) - flit];
    
          /*---------------------------------------------------------------------*/
          /* Resolve base == 0 "%i" case according to the next 2 input characters*/
          /* we cannot decide if base is 16 here. Delay it later when we see 'x".*/
          /*---------------------------------------------------------------------*/
          if (base == 0)
          {
             if (inchar == '0')
             {	 
                /*---------------------------------------------------------------*/
                /* Look ahead at the next characters                             */
                /*---------------------------------------------------------------*/
                look_ahead_char = _inpchar(inp); 
                _uninpchar(inp, look_ahead_char);
    #if !defined(MINIMAL)
    	    if ((look_ahead_char != 'x' && look_ahead_char != 'X'))
    #else
                if (look_ahead_char != 'x')
    #endif
    	       base = 8;
             }
             else /* inchar is not a 0 */
    	    base = 10;
          }
    
          /*---------------------------------------------------------------------*/
          /* hex_conv shows if this number could be interpreted as a hex number. */
          /*---------------------------------------------------------------------*/
    #if !defined(MINIMAL)
          hex_conv = (conv == 'i' || conv =='x' || conv == 'p');
    #else
          hex_conv = (conv == 'x');
    #endif
       }
    
       /*------------------------------------------------------------------------*/
       /* Accept a leading '0' for an octal number, or it could be a leading zero*/
       /* for hex number "0x".                                                   */
       /*------------------------------------------------------------------------*/
       if (w_counter != 0 && (conv == 'o' || hex_conv) && inchar == '0')
    
       {
          seen_leading_zero = 1;
          *(tmpptr++) = inchar;
          inchar = _inpchar(inp);
          (*num_read)++;
          w_counter--;
       }
    
       /*------------------------------------------------------------------------*/
       /* Decide if we can accept a following "x"                                */
       /* To accept this "x",                                                    */
       /* 1) need a leading zero,                                                */
       /* 2) need the curernt input char to be "x",                              */
       /* 3) the look_ahead_char has to be hex number.                           */
       /*------------------------------------------------------------------------*/
    #if !defined(MINIMAL)
       inchar_is_x = (inchar == 'x' || inchar == 'X');
    #else
       inchar_is_x = (inchar == 'x');
    #endif
    
       if (w_counter != 0  && hex_conv && seen_leading_zero == 1 && inchar_is_x)
       {
          /*---------------------------------------------------------------------*/
          /* Look ahead at the next characters                                   */
          /*---------------------------------------------------------------------*/
          look_ahead_char = _inpchar(inp); 
          _uninpchar(inp, look_ahead_char); 
          if (isxdigit(look_ahead_char))
          {
             base = 16;
    	 *(tmpptr++) = inchar;
    	 inchar = _inpchar(inp);
    	 (*num_read)++;
    	 w_counter--;
    	 if (w_counter == 0)
    	 {
                /*---------------------------------------------------------------*/
                /* Now we consumed a leading 0(outer IF), we also consumed a 'x' */
    	    /* (inner IF), but we have no width left for any more number,ex: */
    	    /* rv = _sscanf("0x3", "%2x%c", &i, &c);                         */
    	    /* we need to quit from here, no more further scanning. According*/
    	    /* to Plauger of Dinkumware. The return value should be -1.      */
                /*---------------------------------------------------------------*/
    	    (*num_read) = 0;
    	    return EOF;
    	 }
          }
       }
    
       /*------------------------------------------------------------------------*/
       /* Accept digits 0-7 for octal, digits 0-9 for decimal numbers, or 0-F for*/
       /* hexadecimal numbers based on the base we calcuated before.             */
       /*------------------------------------------------------------------------*/
       while (w_counter != 0 &&
    	  (((base == 8) && (inchar >= '0' && inchar <= '7')) ||
    	   ((base == 10) && (inchar >= '0' && inchar <= '9')) ||    
    	   ((base == 16) && isxdigit(inchar))))
       {
          seen_num = 1;  
          *(tmpptr++) = inchar;
          inchar = _inpchar(inp);
          (*num_read)++;
          w_counter--;
       }
    
       /*------------------------------------------------------------------------*/
       /* Put the last unqualified char back to the input buffer.                */
       /*------------------------------------------------------------------------*/
       _uninpchar(inp, inchar);
       (*num_read)--;
    
       /*------------------------------------------------------------------------*/
       /* Append the terminating NULL character.                                 */
       /*------------------------------------------------------------------------*/
       *tmpptr = '\0';
    
       /*------------------------------------------------------------------------*/
       /* If no number seen, return EOF if EOF is encountered, otherwise, 0      */
       /*------------------------------------------------------------------------*/
       if (seen_leading_zero == 0 && seen_num == 0)
    	return (bnum_read == *num_read && inchar == EOF )? EOF :0;
    
       /*------------------------------------------------------------------------*/
       /* Return 1 if a number is seem and successfully copied to output buffer  */
       /*------------------------------------------------------------------------*/
       return(1);
    }
    
    #if !defined(NOFLOAT) && !defined(MINIMAL)
    /*****************************************************************************/
    /* _SPROC_FLOAT   -  Read a float string into a temporary string             */
    /*                                                                           */
    /*    This function takes the next float in character form from the          */
    /*    current input source, and copies it into a temporary string, where     */
    /*    it can later be converted into a numerical value.                      */
    /*                                                                           */
    /*    Returns:                                                               */
    /*                                                                           */
    /*        EOF if end-of-file was reached before a matching input sequence    */
    /*            (well-formed input item) was found (this is an input failure)  */
    /*                                                                           */
    /*        1   if an input item was found                                     */
    /*                                                                           */
    /*        0   if an input item was not found (this is a matching failure)    */
    /*                                                                           */
    /*****************************************************************************/
    static int _sproc_float(int w_counter, int (*_inpchar)(void **inp), 
                             void (*_uninpchar)(void **inp, int outchar), 
                             char *tmpptr, char conv, void **inp, int *num_read)
    {
       /*------------------------------------------------------------------------*/
       /* Note: w_counter is a parameter that holds the field width.  When       */
       /*       the number of digits specified by w_counter has been read from   */
       /*       input, the function finishes.  w_counter is checked before each  */
       /*       read to make sure that it is not equal to zero, and it is        */
       /*       decremented after each read.  If no field width was specified,   */
       /*       w_counter will be equal to -1, in which case it will never       */
       /*       equal zero, and the function will read from input until it       */
       /*       encounters the first invalid character.                          */
       /*------------------------------------------------------------------------*/
     
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       int inchar;
       int invalid   = 0;
       int bnum_read = *num_read;
       int dec_flag  =  0;
       int e_flag    =  0;
    
       /*------------------------------------------------------------------------*/
       /* Read in the next character                                             */
       /*------------------------------------------------------------------------*/
       inchar = _inpchar(inp);
       if (inchar != EOF) (*num_read)++;
    
       /*------------------------------------------------------------------------*/
       /* Accept the next character if it is a sign                              */
       /*------------------------------------------------------------------------*/
       if ((inchar == '+' || inchar == '-') && w_counter != 0)
       {
          *(tmpptr++) = inchar;
          inchar = _inpchar(inp);
          if (inchar != EOF) (*num_read)++;
          w_counter--;
       }
     
       /*------------------------------------------------------------------------*/
       /* Accept the next character if it is a numerical digit.                  */
       /* The characters '.', 'e', 'E', '+', and '-' are accepted under the      */
       /* following conditions:                                                  */
       /*                                                                        */
       /* '.'         :  a '.', an 'e', or an 'E' has not yet been encountered   */
       /* 'e' or 'E'  :  neither of these characters have been encounterd yet    */
       /* '+' or '-'  :  If the last character read was an 'E' or an 'e'         */
       /*------------------------------------------------------------------------*/
       while ((w_counter != 0) &&
              ((inchar >= '0' && inchar <= '9') || inchar == '.' || inchar == 'e'
               || inchar == 'E' || inchar == '+' || inchar == '-'))
       {
    
          switch (inchar)
          {
             case  '.'   :  if (dec_flag || e_flag) { invalid = 1; break; } 
                            else dec_flag = 1;
                            break;
    
             case  'e'   :
             case  'E'   :  if (e_flag) { invalid = 1; break; }
                            else e_flag = 1;
                            break;
    
             case  '+'   :  
             case  '-'   :  if (*(tmpptr-1) != 'E' && *(tmpptr-1) != 'e')
                            { invalid = 1; break; }
          }
    
          if (invalid) break;
          *(tmpptr++) = inchar;
          inchar = _inpchar(inp);
          if (inchar != EOF) (*num_read)++;
          w_counter--;
       }
    
       _uninpchar(inp, inchar);
       if (inchar != EOF) (*num_read)--;
    
       *tmpptr = '\0';
    
       if (bnum_read == *num_read)
           return inchar == EOF ? EOF : 0;
    
       return(1);
    }
    #endif
    
    /*****************************************************************************/
    /* _SPROC_STR  -  Copy a string from the input source to a temporary string  */
    /*                                                                           */
    /*    This function takes a string from the input source, and copies it      */
    /*    into a temporary string, to be later assigned to a scanf argument.     */
    /*                                                                           */
    /*    Returns:                                                               */
    /*                                                                           */
    /*        EOF if end-of-file was reached before a matching input sequence    */
    /*            (well-formed input item) was found (this is an input failure)  */
    /*                                                                           */
    /*        1   if an input item was found                                     */
    /*                                                                           */
    /*        0   if an input item was not found (this is a matching failure)    */
    /*                                                                           */
    /*****************************************************************************/
    static int _sproc_str(int w_counter, int (*_inpchar)(void **inp), 
                           void (*_uninpchar)(void **inp, int outchar), 
                           char *tmpptr, char conv, void **inp, int *num_read)
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       int inchar;
       int bnum_read = *num_read;
    
       /*------------------------------------------------------------------------*/
       /* If no precision was given for the %c conversion, set it to one.        */
       /*------------------------------------------------------------------------*/
       if ((conv == 'c') && (w_counter < 0)) w_counter = 1;
    
       /*------------------------------------------------------------------------*/
       /* Read in the next character, then while that character is not a white   */
       /* space character, a null terminator, an EOF character, and the field    */
       /* width has not been exceeded, copy it to the temporary string, and      */
       /* get another character.                                                 */
       /*------------------------------------------------------------------------*/
       inchar = _inpchar(inp);
       (*num_read)++;
    
       while ((conv == 'c' || !isspace(inchar)) && inchar != '\0' &&
              inchar != EOF && w_counter--)
       { 
          if (tmpptr) *(tmpptr++) = inchar;
          inchar = _inpchar(inp);
          (*num_read)++;
       }
       
       _uninpchar(inp, inchar);
       (*num_read)--;
    
       /*------------------------------------------------------------------------*/
       /* If no characters were read, an input error occurred.  Do not modify    */
       /* the argument.                                                          */
       /*------------------------------------------------------------------------*/
       if (bnum_read == *num_read) return(EOF);
    
       /*------------------------------------------------------------------------*/
       /* The %s conversion specifies that a null terminator be placed at the    */
       /* end of the conversion.                                                 */
       /*------------------------------------------------------------------------*/
       if (conv == 's' && tmpptr) *tmpptr = '\0';
    
       return(1);
    }
    
    #if !defined(MINIMAL)
    /*****************************************************************************/
    /* _SPROC_LB   -  Process the %[ conversion                                  */
    /*                                                                           */
    /*    This function copies characters from the input stream into a           */
    /*    temporary string until it satisfies the field width, or encounters a   */
    /*    character that is not in the scanset.  The scanset is defined as the   */
    /*    characters passed between the left and right brackets.  If a '^' is    */
    /*    first character after the left bracket, then the scanset is every      */
    /*    character that is not listed between the two brackets.                 */
    /*                                                                           */
    /*    Returns:                                                               */
    /*                                                                           */
    /*        EOF if end-of-file was reached before a matching input sequence    */
    /*            (well-formed input item) was found (this is an input failure)  */
    /*                                                                           */
    /*        1   if an input item was found                                     */
    /*                                                                           */
    /*        0   if an input item was not found (this is a matching failure)    */
    /*                                                                           */
    /*****************************************************************************/
    static int _sproc_lb(int (*_inpchar)(void **inp), 
                          void (*_uninpchar)(void **inp, int outchar),
                          char *tmpptr, _SFIELD *sfield, void **inp, int *num_read)
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       int bnum_read = *num_read;
       int w_counter =  sfield->fwidth;
       int negate = (_STCHK(sfield, _SFCIRC) != 0);
    
       /*------------------------------------------------------------------------*/
       /* This loop iterates until one of the following conditions occurs:       */
       /* 1) EOF is reached                                                      */
       /* 2) the input character doesn't match the scan set                      */
       /* 3) sfield->fwidth (field width) characters were read.                  */
       /*------------------------------------------------------------------------*/
       for (; w_counter != 0; w_counter--)
       {
          int inchar = _inpchar(inp);
    
          if (inchar != EOF &&
              (negate ^ (strrchr(sfield->scanset, inchar) != NULL)))
          {
             *(tmpptr++) = inchar;
             (*num_read)++;
          }
          else
          {
             _uninpchar(inp, inchar);
    
             /*------------------------------------------------------------------*/
             /* If we haven't successfully read any characters, this is either a */
             /* matching failure (input character didn't match scan set) or      */
             /* input failure (EOF reached). In both cases, the conversion fails */
             /* and the output buffer is not null-terminated.                    */
             /*------------------------------------------------------------------*/
             if (bnum_read == *num_read)
                return inchar == EOF ? EOF : 0;
    
             break;
          }
       }
    
       *tmpptr = '\0';
       return(1);
    }
    #endif
    
    /*****************************************************************************/
    /* _SSET_ARG   -  Assign the converted value to the next argument            */
    /*                                                                           */
    /*    This function takes a pointer to the result conversion string, and     */
    /*    assigns it to the next argument.  The type of argument to be assigned  */
    /*    is determined by the conversion specifier, and the h, l, or L flags    */
    /*    if they were used.                                                     */
    /*                                                                           */
    /*****************************************************************************/
    static void _sset_arg(_SFIELD *sfield, va_list *_ap, char *tmpbuf)
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       int base = 0; /* assumes %i until otherwise set */
    
       /*------------------------------------------------------------------------*/
       /* Do the assignment only if the result string has a length greater than  */
       /* zero, and the '*' flag was not used                                    */
       /*------------------------------------------------------------------------*/
       if (tmpbuf[0] != '\0' && !_STCHK(sfield, _SFSTAR))
          switch (sfield->conv)
          {
             case  'd'   :  base = 10;
    #if !defined(MINIMAL)
             case  'i'   :
    #endif
       
    #if !defined(MINIMAL)
                            switch (_STCHK(sfield, 
                                          (_MFH | _MFHH | _MFL | _MFLL | _MFI40)))
                            {
                               case  _MFH  :  *(va_arg(*_ap, short int*)) =
                                              (short int)strtol(tmpbuf, NULL,
                                              base);
                                              break;
    
                               case  _MFHH :  *(va_arg(*_ap, char*)) =
                                              (char)strtol(tmpbuf, NULL, base);
                                              break;
    
                               case _MFL   :  *(va_arg(*_ap, long int*)) =
                                              strtol(tmpbuf, NULL, base);
                                              break;
    #ifdef LLONG_MAX
                               case _MFLL  :  *(va_arg(*_ap, long long int*)) =
                                              strtoll(tmpbuf, NULL, base);
                                              break;
    #endif
    #ifdef __TI_INT40_T__
                               case _MFI40 :  *(va_arg(*_ap, __int40_t*)) =
                                              strtoll(tmpbuf, NULL, base);
                                              /* use strtoll as we don't have
                                               * strtoi40() */
                                              break;
    #endif
                               default     :
    #endif /* !defined(MINIMAL) */
                                              *(va_arg(*_ap, int*)) =
                                              (int)strtol(tmpbuf, NULL, base);
    #if !defined(MINIMAL)
                                              break;
                            }
    #endif
                            
                            break;
    
          /*---------------------------------------------------------------------*/
          /* Suppress "conversion from integer to smaller pointer" warning for   */
          /* the %p case. Also suppress the bad cast from integral to pointer.   */
          /*---------------------------------------------------------------------*/
    #if !defined(MINIMAL)
    #pragma diag_suppress 1107,173
          case  'p'   :  *(va_arg(*_ap, void **))=(void *)(uintptr_t)strtoul(tmpbuf, NULL, 16);
    		     break;
    #pragma diag_default 1107,173
    #endif
    
    #if !defined(MINIMAL)
          case  'u'   :
          case  'x'   :
          case  'o'   :  
                         base = (sfield->conv == 'u') ? 10 :
                                (sfield->conv == 'x') ? 16 : 8;
    #else
          case  'x'   :
          case  'o'   :  
                         base = (sfield->conv == 'x') ? 16 : 8;
    #endif
    
    #if !defined(MINIMAL)
                         switch (_STCHK(sfield, 
                                       (_MFH | _MFHH | _MFL | _MFLL | _MFI40)))
                         {
                            case _MFH : *(va_arg(*_ap, unsigned short int*))=
                                        (unsigned short int)strtoul(tmpbuf,
                                        NULL, base);
                                        break;
    
                            case _MFHH: *(va_arg(*_ap, unsigned char*))=
                                        (unsigned char)strtoul(tmpbuf, NULL, base);
                                        break;
    
                            case _MFL : *(va_arg(*_ap, unsigned long int*)) =
                                        strtoul(tmpbuf, NULL, base);
                                        break;
    #ifdef LLONG_MAX
                            case _MFLL: *(va_arg(*_ap, unsigned long long int*)) =
                                        strtoull(tmpbuf, NULL, base);
                                        break;
    #endif
    #ifdef __TI_INT40_T__
                            case _MFI40: *(va_arg(*_ap, unsigned __int40_t*)) =
                                        (unsigned __int40_t)
                                                 strtoull(tmpbuf, NULL, base);
                                        break;
    #endif
                            default   : 
    #endif /* !defined(MINIMAL) */
                                        *(va_arg(*_ap, unsigned int*)) =
                                        (unsigned int)strtoul(tmpbuf, NULL,
                                        base);
    #if !defined(MINIMAL)
                                        break;
                         }
    #endif
                         break;
    
    #if !defined(NOFLOAT) && !defined(MINIMAL)
          case  'e'   :
          case  'f'   :
          case  'g'   :
          case  'E'   :
          case  'G'   :  switch (_STCHK(sfield, (_MFL | _MFLD)))
                         {
                            case _MFL : *(va_arg(*_ap, double*))=
                                        strtod(tmpbuf, NULL);
                                        break;
    
                            case _MFLD: *(va_arg(*_ap, long double*)) =
                                        strtold(tmpbuf, NULL);
                                        break;
    
                            default   : *(va_arg(*_ap, float*)) =
                                        (float)strtod(tmpbuf, NULL);
                                        break;
                         }
                         break;
    #endif
       }
    }
    
    I believe _scanf() and __TI_scanfi() are the same.

    The main function in the file is __TI_scanfi

    From here, I see a bunch of functions: isspace, _inpchar, _uninpchar, memset, _chkmbc, _sget_conv, _sproc_int, _sproc_float, va_arg, _sproc_str, _sproc_lb, _sset_arg.

    These are defined in _scanfi.c:

    _sget_conv

    _sproc_int

    _sproc_float

    _sproc_str

    _sproc_lb

    _sset_arg

    I am a bit stuck here. E.G. isspace in the src folder goes to this:

    #undef _INLINE
    #include <ctype.h> 
    
    _CODE_ACCESS int isspace(int c)
    {
        return(_isspace(c));
    }

    _inpchar cannot be found.

    Could you direct me to where exactly fgetc and ungetc are used?

     

  • Rodney Wong said:
    Could you direct me to where exactly fgetc and ungetc are used?

    The RTS library source code is in a directory name similar to ...

    C:\ti\ccsv6\tools\compiler\ti-cgt-msp430_4.4.4\lib\src

    The function scanf is implemented in fscanf.c.  It calls the function __TI_scanfi.  The prototype for __TI_scanfi is in format.h.

      int __TI_scanfi(void *inp, const char *_format, va_list _ap,
                      int (*_chkmbc)(void **inp, char **_format, int *num_read),
                      int (*_inpchar)(void **inp),
                      void (*_uninpchar)(void **inp, int outchar));

    The implementation of __TI_scanfi is in _scanfi.c.  The implementation function name appears to be _SCANFI.  There is some preprocessor code regarding that name and the minimal and nofloat versions of scanf, none of which is explained here.  In this post _SCANFI and __TI_scanfi are the same.  The interesting argument is inpchar.  This is a pointer to a function which takes a void **inp as an argument, and returns int.  This function is called to get the next input character.

    Back in fscanf.c, the function scanf calls __TI_scanfi like this ...

       result = (__TI_scanfi((void *)stdin, _fmt, _ap, _chkmbc, _inpchar, _uninpchar));

    The function _inpchar is passed to get the next input character.  This is a static function implemented in fscanf.c ...

    static int _inpchar(void **inp) { return (fgetc((FILE *)(*inp))); }

    This function calls fgetc.

    And this shows how calling scanf means fgetc is used to obtain the input characters.  A similar relationship exists between the function pointer _uninpchar and ungetc.

    Thanks and regards,

    -George

  • I modified fgetc like fputc. 

                    int _c = 0;
    
    		if( i == 0) {
    			i++;
    			return '0';
    		}
    
    		while(!(UCA1IFG&UCRXIFG)); // should time out
    		_c = UCA1RXBUF;
    		UCA1IFG &= ~UCRXIFG;
    
    		if( _c != 13 & _c != 10) {
    			i++;
    			return _c;
    		}
    
    		if( _c == 13 ) {
    			i = 0;
    			return 0;
    		}
    
    		if(_c == 10) {
    			i = 0;
    			return 0;
    		}
    
    		printf("\r\nfgetc BUG!\r\n");
    		i = 0;
    		return 0;

    For some reason, scanf is not recognizing the first letter entered in the console. That is why I added this:

    f( i == 0) {
    	i++;
            return '0';
    }

    This sends scanf a '0' character before scanf actually starts reading.

    Why doesn't scanf read the first letter? 

  • Rodney Wong said:
    Why doesn't scanf read the first letter? 

    We lack the low level expertise required on MSP430 to answer this question.  I suggest you start a new thread in the MSP device forum.

    Thanks and regards,

    -George