/****************************************************************************
 * apps/testing/scanftest/scanftest_main.c
 *
 *   Copyright (C) 2005-01-26, Greg King (https://github.com/cc65)
 *
 * Original License:
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not
 *    be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *   Modified: Johannes Schock
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name NuttX 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.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <libgen.h>
#include <errno.h>
#include <debug.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#define ARRAYSIZE(a) (sizeof (a) / sizeof (a)[0])

/****************************************************************************
 * Private Data
 ****************************************************************************/

/****************************************************************************
 * Name: cmd_basename
 ****************************************************************************/

static const struct
{
  FAR const char *input;
  FAR const char *format;
  int rvalue;
  enum TYPE
  {
    INT,
    CHAR,
    FLOAT,
    DOUBLE
  } type1;
  union
  {
    int nvalue;
    float fvalue;
    double dvalue;
    const char *svalue;
  } v1;
  enum TYPE type2;
  union
  {
    int nvalue;
    float fvalue;
    double dvalue;
    const char *svalue;
  } v2;
}
test_data[] =
{
  /* Input sequences for character specifiers must be less than 80 characters
   * long.  These format strings are allowwed a maximum of two assignment
   * specifications.
   */

  /* Test that literals match, and that they aren't seen as conversions. **
   * Test that integer specifiers can handle end-of-file.
   */

  {
    "qwerty   Dvorak", "qwerty  Dvorak", 0, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 1 */
  {
    "qwerty", "qwerty  %d%i", EOF, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 2 */
  {
    "qwerty   ", "qwerty  %d%i", EOF, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 3 */

  /* Test that integer specifiers scan properly. */

  {
    "qwerty   a", "qwerty  %d%i", 0, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 4 */
  {
    "qwerty   -", "qwerty  %d%i", 0, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 5 */
  {
    "qwerty   -9", "qwerty  %d%i", 1, INT,
    {
      .nvalue = -9
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 6 */
  {
    "qwerty   -95", "qwerty  %d%i", 1, INT,
    {
      .nvalue = -95
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 7 */
  {
    "qwerty   -95a", "qwerty  %d%i", 1, INT,
    {
      .nvalue = -95
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 8 */
  {
    "qwerty   -95a 1", "qwerty  %d%i", 1, INT,
    {
      .nvalue = -95
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 9 */
  {
    "qwerty   -a", "qwerty  %d%i", 0, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 10 */
  {
    "qwerty   -95 1", "qwerty  %d%i", 2, INT,
    {
      .nvalue = -95
    },
    INT,
    {
      .nvalue = 1
    }
  },                            /* 11 */
  {
    "qwerty    95  2", "qwerty  %i", 1, INT,
    {
      .nvalue = 95
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 12 */
  {
    "qwerty   -95 +2", "qwerty  %x%o", 2, INT,
    {
      .nvalue = -0x95
    },
    INT,
    {
      .nvalue = 2
    }
  },                            /* 13 */
  {
    "qwerty  0x9e 02", "qwerty  %i%i", 2, INT,
    {
      .nvalue = 0x9e
    },
    INT,
    {
      .nvalue = 2
    }
  },                            /* 14 */
  {
    "qwerty   095  2", "qwerty  %i%i", 2, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 95
    }
  },                           /* 15 */
  {
    "qwerty   0e5  2", "qwerty  %i%i", 1, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                            /* 16 */

  /* Test that character specifiers can handle end-of-file. */

  {
    "qwerty", "qwerty  %s%s", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 17 */
  {
    "qwerty   ", "qwerty  %s%s", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 18 */
  {
    "qwerty", "qwerty  %c%c", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 19 */
  {
    "qwerty   ", "qwerty  %c%c", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 20 */
  {
    "qwerty", "qwerty  %[ a-z]%c", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 21 */
  {
    "qwerty   ", "qwerty  %[ a-z]%c", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 22 */
  {
    "qwerty   ", "qwerty%s%s", EOF, CHAR,
    {
      .svalue = ""
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 23 */

  /* Test that character specifiers scan properly. */

  {
    "123456qwertyasdfghzxcvbn!@#$%^QWERTYASDFGHZXCV"
      "BN7890-=uiop[]\\jkl;'m,./&*()_+UIOP{}|JKL:\"M<>?", "%79s%79s", 2, CHAR,
    {
      .svalue = "123456qwertyasdfghzxcvbn!@#$%^QWERTYASDFGHZXCV"
                "BN7890-=uiop[]\\jkl;'m,./&*()_+UIO"
    },
    CHAR,
    {
      .svalue = "P{}|JKL:\"M<>?"
    }
  },                           /* 24 */
  {
    "qwerty   ", "qwerty%c%c", 2, CHAR,
    {
      .svalue = " "
    },
    CHAR,
    {
    .svalue = " "
    }
  },                           /* 25 */
  {
    "qwerty   ", "qwerty%2c%c", 2, CHAR,
    {
      .svalue = "  "
    },
    CHAR,
    {
      .svalue = " "
    }
  },                           /* 26 */
  {
    "qwerty   ", "qwerty%2c%2c", 1, CHAR,
    {
      .svalue = "  "
    },
    CHAR,
    {
      .svalue = " "
    }
  },                           /* 27 */
  {
    "qwerty   ", "qwerty%[ a-z]%c", 1, CHAR,
    {
      .svalue = "   "
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 28 */
  {
    "qwerty  q", "qwerty%[ a-z]%c", 1, CHAR,
    {
      .svalue = "  q"
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 29 */
  {
    "qwerty  Q", "qwerty%[ a-z]%c", 2, CHAR,
    {
      .svalue = "  "
    },
    CHAR,
    {
      .svalue = "Q"
    }
  },                           /* 30 */
  {
    "qwerty-QWERTY-", "%[q-ze-]%[-A-Z]", 2, CHAR,
    {
      .svalue = "qwerty-"
    },
    CHAR,
    {
      .svalue = "QWERTY-"
    }
  },                           /* 31 */

  /* Test the space-separation of strings. */

  {
    "qwerty qwerty", "qwerty%s%s", 1, CHAR,
    {
      .svalue = "qwerty"
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 32 */
  {
    "qwerty qwerty Dvorak", "qwerty%s%s", 2, CHAR,
    {
      .svalue = "qwerty"
    },
    CHAR,
    {
      .svalue = "Dvorak"
    }
  },                           /* 33 */

  /* Test the mixxing of types. */

  {
    "qwerty  abc3", "qwerty%s%X", 1, CHAR,
    {
      .svalue = "abc3"
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 34 */
  {
    "qwerty  abc3", "qwerty%[ a-z]%X", 2, CHAR,
    {
      .svalue = "  abc"
    },
    INT,
    {
      .nvalue = 3
    }
  },                           /* 35 */
  {
    "qwerty  abc3", "qwerty%[ a-z3]%X", 1, CHAR,
    {
      .svalue = "  abc3"
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 36 */
  {
    "qwerty  abc3", "qwerty%[ A-Z]%X", 2, CHAR,
    {
      .svalue = "  "
    },
    INT,
    {
      .nvalue = 0xabc3
    }
  },                           /* 37 */
  {
    "qwerty  3abc", "qwerty%i%[ a-z]", 2, INT,
    {
      .nvalue = 3
    },
    CHAR,
    {
      .svalue = "abc"
    }
  },                           /* 38 */
  {
    "qwerty  3abc", "qwerty%i%[ A-Z]", 1, INT,
    {
      .nvalue = 3
    },
    CHAR,
    {
      .svalue = ""
    }
  },                           /* 39 */

  /* Test the character-count specifier. */

  {
    "  95 5", "%n%i", 1, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 95
    }
  },                          /* 40 */
  {
    "  a5 5", "%n%i", 0, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 41 */
  {
    "  a5 5", "%x%n", 1, INT,
    {
      .nvalue = 0xa5
    },
    INT,
    {
      .nvalue = 4
    }
  },                           /* 42 */
  {
    "  a5 5", " %4c%n", 1, CHAR,
    {
      .svalue = "a5 5"
    },
    INT,
    {
      .nvalue = 6
    }
  },                           /* 43 */
  {
    " 05a9", "%i%n", 1, INT,
    {
      .nvalue = 5
    },
    INT,
    {
      .nvalue = 3
    }
  },                           /* 44 */

  /* Test assignment-suppression. */

  {
    "  95 6", "%n%*i", 0, INT,
    {
      .nvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 45 */
  {
    "  a5 6", "%*x%n", 0, INT,
    {
      .nvalue = 4
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 46 */
  {
    "  a5 6", "%*x%n%o", 1, INT,
    {
      .nvalue = 4
    },
    INT,
    {
      .nvalue = 6
    }
  },                           /* 47 */
  {
    "  a5 6", " %*4c%d", 0, CHAR,
    {
      .svalue = ""
    },
    INT,
    {
      .nvalue = 0
    }
  },                          /* 48 */
  {
    "The first number is 7.  The second number is 8.\n",
      "%*[ .A-Za-z]%d%*[ .A-Za-z]%d", 2, INT,
    {
      .nvalue = 7
    },
    INT,
    {
       .nvalue = 8
    }
  },                           /* 49 */

  /* Test that float specifiers can handle end-of-file. */

  {
    "qwerty", "qwerty  %f%i", EOF, FLOAT,
    {
      .fvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 50 */
  {
    "qwerty   ", "qwerty  %f%i", EOF, FLOAT,
    {
      .fvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 51 */

  /* Test that float specifiers scan properly. */

  {
    "qwerty   a", "qwerty  %f%i", 0, FLOAT,
    {
      .fvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 52 */
  {
    "qwerty   -", "qwerty  %f%i", 0, FLOAT,
    {
      .fvalue = 0
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 53 */
  {
    "qwerty   9.87654321", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = 9.87654321f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 54 */
  {
    "qwerty   +9.87654321", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = 9.87654321f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 55 */
  {
    "qwerty   -9.87654321", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = -9.87654321f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 56 */
  {
    "qwerty   9.87654321E8", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = 9.87654321E8f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 57 */
  {
    "qwerty   +9.87654321E+8", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = 9.87654321E8f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 58 */
  {
    "qwerty   -9.87654321e8", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = -9.87654321E8f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 59 */
  {
    "qwerty   9.87654321E-8", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = 9.87654321E-8f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 60 */
  {
    "qwerty   -9.87654321e-8", "qwerty  %f%i", 1, FLOAT,
    {
      .fvalue = -9.87654321E-8f
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 61 */
  {
    "qwerty   9.87654321", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = 9.87654321l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 62 */
  {
    "qwerty   +9.87654321", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = 9.87654321l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 63 */
  {
    "qwerty   -9.87654321", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = -9.87654321l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 64 */
  {
    "qwerty   9.87654321e8", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = 9.87654321E8l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 65 */
  {
    "qwerty   +9.87654321e+8", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = 9.87654321E8l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 66 */
  {
    "qwerty   -9.87654321E8", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = -9.87654321E8l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 67 */
  {
    "qwerty   9.87654321e-8", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = 9.87654321E-8l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 68 */
  {
    "qwerty   -9.87654321E-8", "qwerty  %lf%i", 1, DOUBLE,
    {
      .dvalue = -9.87654321E-8l
    },
    INT,
    {
      .nvalue = 0
    }
  },                           /* 69 */
};

/* Test the char, short, and long specification-modifiers. */

static const struct
{
  FAR const char *input;
  FAR const char *format;
  union
  {
    long long s;
    unsigned long long u;
  } value;
  enum MODTYPE
  {
    HH_MOD_S,
    HH_MOD_U,
    H_MOD_S,
    H_MOD_U,
    NO_MOD_S,
    NO_MOD_U,
    L_MOD_S,
    L_MOD_U,
    LL_MOD_S,
    LL_MOD_U
  } type;
}
type_data[] =
{
  {
    " 123456789", "%hhd",
    {
      .s = (signed char)123456789L
    },
    HH_MOD_S
  },                           /*  1 */
  {
    "+123456789", "%hhd",
    {
      .s = (signed char)123456789L
    },
    HH_MOD_S
  },                           /*  2 */
  {
    "-123456789", "%hhd",
    {
      .s = (signed char)-123456789L
    },
    HH_MOD_S
  },                           /*  3 */
  {
    "+123456789", "%hhu",
    {
      .u = (unsigned char)123456789L
    },
    HH_MOD_U
  },                           /*  4 */
  {
    "-123456789", "%hhu",
    {
      .u = (unsigned char)-123456789L
    },
    HH_MOD_U
  },                           /*  5 */
  {
    " 123456789", "%hd",
    {
      .s = (signed short)123456789L
    },
    H_MOD_S
  },                           /*  6 */
  {
    "+123456789", "%hd",
    {
      .s = (signed short)123456789L
    },
    H_MOD_S
  },                           /*  7 */
  {
    "-123456789", "%hd",
    {
      .s = (signed short)-123456789L
    },
    H_MOD_S
  },                           /*  8 */
  {
    "+123456789", "%hu",
    {
      .u = (unsigned short)123456789L
    },
    H_MOD_U
  },                           /*  9 */
  {
    "-123456789", "%hu",
    {
      .u = (unsigned short)-123456789L
    },
    H_MOD_U
  },                           /* 10 */
  {
    " 123456789", "%d",
    {
      .s = (signed int)123456789L
    },
    NO_MOD_S
  },                           /* 11 */
  {
    "+123456789", "%d",
    {
      .s = (signed int)123456789L
    },
    NO_MOD_S
  },                           /* 12 */
  {
    "-123456789", "%d",
    {
      .s = (signed int)-123456789L
    },
    NO_MOD_S
  },                           /* 13 */
  {
    "+123456789", "%u",
    {
      .u = (unsigned int)123456789L
    },
    NO_MOD_U
  },                           /* 14 */
  {
    "-123456789", "%u",
    {
      .u = (unsigned int)-123456789L
    },
    NO_MOD_U
  },                           /* 15 */
  {
    " 123456789", "%ld",
    {
      .s = (signed long)123456789L
    },
    L_MOD_S
  },                           /* 16 */
  {
    "+123456789", "%ld",
    {
      .s = (signed long)123456789L
    },
    L_MOD_S
  },                           /* 17 */
  {
    "-123456789", "%ld",
    {
      .s = (signed long)-123456789L
    },
    L_MOD_S
  },                           /* 18 */
  {
    "+123456789", "%lu",
    {
      .u = (unsigned long)123456789L
    },
    L_MOD_U
  },                           /* 19 */
  {
    "-123456789", "%lu",
    {
      .u = (unsigned long)-123456789L
    },
    L_MOD_U
  },                           /* 20 */
  {
    " 123456789123456789", "%lld",
    {
      .s = (signed long long)123456789123456789LL
    },
    LL_MOD_S
  },                           /* 21 */
  {
    "+123456789123456789", "%lld",
    {
      .s = (signed long long)123456789123456789LL
    },
    LL_MOD_S
  },                           /* 22 */
  {
    "-123456789123456789", "%lld",
    {
      .s = (signed long long)-123456789123456789LL
    },
    LL_MOD_S
  },                           /* 23 */
  {
    "+123456789123456789", "%llu",
    {
      .u = (unsigned long long)123456789123456789LL
    },
    LL_MOD_U
  },                           /* 24 */
  {
    "-123456789123456789", "%llu",
    {
      .u = (unsigned long long)-123456789123456789LL
    },
    LL_MOD_U
  },                           /* 25 */
};

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * scanftest_main
 ****************************************************************************/

int main(int argc, FAR char *argv[])
{
  int t;
  int i;
  int c;
  int n1 = 12345;
  int n2;
  bool ok;
  char s1[80];
  char s2[80];
  float f1;
  float f2;
  double d1;
  double d2;
  FAR FILE *fp;

  FAR const char *teststring = "teststring a";
  FAR const char *fname = "/mnt/fs/test.txt";

  /* Test that scanf() can recognize percent-signs in the input. ** Test that
   * integer converters skip white-space. ** Test that "%i" can scan a single
   * zero digit (followed by EOF).
   */

  sscanf("%  \n\f\v\t  0", "%%%i", &n1);
  if (n1 != 0)
    {
      printf("sscanf()'s \"%%%%%%i\" couldn't scan either a \"%%\" "
             "or a single zero digit.\n\n");
    }

  /* Test scanf()'s return-value: EOF if input ends before the first *
   * conversion-attempt begins; an assignment-count, otherwise. * Test that
   * scanf() properly converts and assigns the correct number * of arguments.
   */

  for (i = 0; i < 2; i++)
    {
      if (i)
        {
          char s3[3];

          printf("\nBack to Back Test...\n");

          memset(s1, '\0', sizeof s1);
          memset(s2, '\0', sizeof s2);
          memset(s3, '\0', sizeof s3);

          fp = fopen(fname, "wb");
          if (fp)
            {
              fputs(teststring, fp);
              fclose(fp);
              fp = fopen(fname, "rb");
              if (fp != NULL)
                {
                  fscanf(fp, "%s", s2);
                  fscanf(fp, "%2c", s3);
                  sprintf(s1, "%s%s", s2, s3);

                  if (strcmp(s1, teststring) != 0)
                    {
                      printf("Error %s != %s.\n", teststring, s1);
                    }
                  else
                    {
                      printf("Test PASSED.\n");
                    }
                }
              else
                {
                  printf("Error opening %s for read.\n", fname);
                }
            }
          else
            {
              printf("Error opening %s for write.\n", fname);
            }
        }

      printf("\nTesting %cscanf()'s return-value,\nconversions, and "
             "assignments...\n",
             i ? 'f' : 's');

      for (t = 0; t < ARRAYSIZE(test_data); ++t)
        {
          /* Prefill the arguments with zeroes. */

          f1 = f2 = d1 = d2 = n1 = n2 = 0;
          memset(s1, '\0', sizeof s1);
          memset(s2, '\0', sizeof s2);

          ok = true;

          if (i)
            {
              fp = fopen(fname, "wb");
              if (fp)
                {
                  fputs(test_data[t].input, fp);
                  fclose(fp);
                }
              else
                {
                  printf("Error opening %s for write.\n", fname);
                  break;
                }

              fp = fopen(fname, "rb");
              if (fp)
                {
                  c = fscanf
                  (fp, test_data[t].format,

                  /* Avoid warning messages about different  pointer-
                   * types, by casting them to void-pointers.
                   */

                  test_data[t].type1 == INT ? (FAR void *)&n1 :
                    test_data[t].type1 == FLOAT ? (FAR void *)&f1 :
                      test_data[t].type1 == DOUBLE ? (FAR void *)&d1 :
                        (FAR void *)s1,
                  test_data[t].type2 == INT ? (FAR void *)&n2 :
                    test_data[t].type2 == FLOAT ? (FAR void *)&f2 :
                      test_data[t].type2 == DOUBLE ? (FAR void *)&d2 :
                        (FAR void *)s2
                  );

                  fclose(fp);
                }
              else
                {
                  printf("Error opening %s for read.\n", fname);
                  break;
                }
            }
          else
            {
              c = sscanf
              (test_data[t].input, test_data[t].format,

              /* Avoid warning messages about different pointer-types, by
               * casting them to void-pointers.
               */

              test_data[t].type1 == INT ? (FAR void *)&n1 :
                test_data[t].type1 == FLOAT ? (FAR void *)&f1 :
                  test_data[t].type1 == DOUBLE ? (FAR void *)&d1 :
                    (FAR void *)s1,
              test_data[t].type2 == INT ? (FAR void *)&n2 :
                test_data[t].type2 == FLOAT ? (FAR void *)&f2 :
                  test_data[t].type2 == DOUBLE ? (FAR void *)&d2 :
                    (FAR void *)s2
              );
            }
          if (c != test_data[t].rvalue)
            {
              printf("Test #%u returned %d instead of %d.\n", t + 1, c,
                     test_data[t].rvalue);
              ok = false;
            }

          if (test_data[t].type1 == INT)
            {
              if (test_data[t].v1.nvalue != n1)
                {
                  printf("Test #%u assigned %i, instead of %i,\n"
                         "\tto the first argument.\n\n", t + 1, n1,
                         test_data[t].v1.nvalue);
                  ok = false;
                }
            }
          else if (test_data[t].type1 == FLOAT)
            {
              if (test_data[t].v1.fvalue != f1)
                {
                  printf("Test #%u assigned %e, instead of %e,\n"
                         "\tto the first argument.\n\n", t + 1, f1,
                         test_data[t].v1.fvalue);
                  ok = false;
                }
            }
          else if (test_data[t].type1 == DOUBLE)
            {
              if (test_data[t].v1.dvalue != d1)
                {
                  printf("Test #%u assigned %le, instead of %le,\n"
                         "\tto the first argument.\n\n", t + 1, d1,
                         test_data[t].v1.dvalue);
                  ok = false;
                }
            }
          else
            {
              /* test_data[t].type1 == CHAR */

              if (strcmp(test_data[t].v1.svalue, s1))
                {
                  printf("Test #%u assigned\n\"%s\",\n"
                         "\tinstead of\n\"%s\",\n"
                         "\tto the first argument.\n\n", t + 1, s1,
                         test_data[t].v1.svalue);
                  ok = false;
                }
            }

          if (test_data[t].type2 == INT)
            {
              if (test_data[t].v2.nvalue != n2)
                {
                  printf("Test #%u assigned %i, instead of %i,\n"
                         "\tto the second argument.\n\n", t + 1, n2,
                         test_data[t].v2.nvalue);
                  ok = false;
                }
            }
          else if (test_data[t].type2 == FLOAT)
            {
              if (test_data[t].v2.fvalue != f2)
                {
                  printf("Test #%u assigned %e, instead of %e,\n"
                         "\tto the second argument.\n\n", t + 1, f2,
                         test_data[t].v2.fvalue);
                  ok = false;
                }
            }
          else if (test_data[t].type2 == DOUBLE)
            {
              if (test_data[t].v2.dvalue != d2)
                {
                  printf("Test #%u assigned %le, instead of %le,\n"
                         "\tto the second argument.\n\n", t + 1, d2,
                         test_data[t].v2.dvalue);
                  ok = false;
                }
            }
          else
            {
              /* test_data[t].type2 == CHAR */

              if (strcmp(test_data[t].v2.svalue, s2))
                {
                  printf("Test #%u assigned\n\"%s\",\n"
                         "\tinstead of\n\"%s\",\n"
                         "\tto the second argument.\n\n", t + 1, s2,
                         test_data[t].v2.svalue);
                  ok = false;
                }
            }

          if (ok)
            {
              printf("Test #%u PASSED.\n", t + 1);
            }
        }
    }

  /* Test the char, short, and long specification-modifiers. */

  printf("\nTesting scanf()'s type-modifiers...\n");
  for (t = 0; t < ARRAYSIZE(type_data); ++t)
    {
      unsigned char hhu;
      unsigned short hu;
      unsigned int nou;
      unsigned long lu;
      unsigned long long llu;
      signed char hhs;
      signed short hs;
      signed int nos;
      signed long ls;
      signed long long lls;

      ok = true;
      switch (type_data[t].type)
        {
        case HH_MOD_S:
          hhs = 0L;
          sscanf(type_data[t].input, type_data[t].format, &hhs);
          if (type_data[t].value.s != hhs)
            {
              printf("Test #%u assigned %hhd instead of %lli.\n", t + 1,
                     hhs, type_data[t].value.s);
              ok = false;
            }
          break;

        case HH_MOD_U:
          hhu = 0L;
          sscanf(type_data[t].input, type_data[t].format, &hhu);
          if (type_data[t].value.u != hhu)
            {
              printf("Test #%u assigned %hhu instead of %lli.\n",
                     t + 1, hhu, type_data[t].value.u);
              ok = false;
            }
          break;

        case H_MOD_S:
          hs = 0L;
          sscanf(type_data[t].input, type_data[t].format, &hs);
          if (type_data[t].value.s != hs)
            {
              printf("Test #%u assigned %hd instead of %lli.\n",
                     t + 1, hs, type_data[t].value.s);
              ok = false;
            }
          break;

        case H_MOD_U:
          hu = 0L;
          sscanf(type_data[t].input, type_data[t].format, &hu);
          if (type_data[t].value.u != hu)
            {
              printf("Test #%u assigned %hu instead of %lli.\n",
                     t + 1, hu, type_data[t].value.u);
              ok = false;
            }
          break;

        case NO_MOD_S:
          nos = 0L;
          sscanf(type_data[t].input, type_data[t].format, &nos);
          if (type_data[t].value.s != nos)
            {
              printf("Test #%u assigned %d instead of %lli.\n",
                     t + 1, nos, type_data[t].value.s);
              ok = false;
            }
          break;

        case NO_MOD_U:
          nou = 0L;
          sscanf(type_data[t].input, type_data[t].format, &nou);
          if (type_data[t].value.u != nou)
            {
              printf("Test #%u assigned %nou instead of %lli.\n",
                     t + 1, nou, type_data[t].value.u);
              ok = false;
            }
          break;

        case L_MOD_S:
          ls = 0L;
          sscanf(type_data[t].input, type_data[t].format, &ls);
          if (type_data[t].value.s != ls)
            {
              printf("Test #%u assigned %ld instead of %lli.\n",
                     t + 1, ls, type_data[t].value.s);
              ok = false;
            }
          break;

        case L_MOD_U:
          lu = 0L;
          sscanf(type_data[t].input, type_data[t].format, &lu);
          if (type_data[t].value.u != lu)
            {
              printf("Test #%u assigned %lu instead of %lli.\n",
                     t + 1, lu, type_data[t].value.u);
              ok = false;
            }
          break;

        case LL_MOD_S:
          lls = 0L;
          sscanf(type_data[t].input, type_data[t].format, &lls);
          if (type_data[t].value.s != lls)
            {
              printf("Test #%u assigned %lld instead of %lli.\n",
                     t + 1, lls, type_data[t].value.s);
              ok = false;
            }
          break;

        case LL_MOD_U:
          llu = 0L;
          sscanf(type_data[t].input, type_data[t].format, &llu);
          if (type_data[t].value.u != llu)
            {
              printf("Test #%u assigned %llu instead of %lli.\n",
                     t + 1, llu, type_data[t].value.u);
              ok = false;
            }
          break;
        }

      if (ok)
        {
          printf("Test #%u PASSED.\n", t + 1);
        }
    }

  return OK;
}
